Musical and lyrical analysis of Pearl Jam’s songs

This repository comprises a musical and lyrical analysis of Pearl Jam’s songs. I use data from Spotify’s and Genius’s APIs. I use scripts to query information on the musical propety of all of the 11 Pearl Jam albums. I later use a script to scrape the lyrycs to several songs and finally use the Genius API to download the remaining. Related works include Kendrick Lamar sentiment analysis, Gloom Index to find Radiohead’s most depressing song by Charlie Thompson, Bob Dylan lyrical analysis by Paul Reiners, tidy sentiment analysis on Prince’s music by Debbie Liske and Musical Lyrics Analysis on several artists by Bree McLennan.

The repo is organized as follows:

  • Data Assessment
    • Intellectual Property (Copyrigths)
    • Songs selection: Spotify API
    • Lyrics: Genius API
  • Data exploration
    • Tokens & data wrangling
    • Gloom Index
    • Word counts by album and song
    • Wordclouds
    • Vocabulary diversity
    • Term Frequency Inverse Document Frequency (TF-IDF)
  • Sentiment Analysis and Natural Language Processing
    • NCR Sentiment
    • Bi-grams and tri-grams

Data Assessment

Intellectual Property (Copyrigths)

I would like to acknowledge that every single content exposed in this repository is based on protected songs. All the rigths of the data used come from the Spotify API, Genius API, but mainly the sonwriters and composers of the songs. In no way it is intented to make it as my own. All the mistakes made are my own and no one else.

Songs selection: Spotify API

I first asing all the packages needed into the vector packages. In this section the important package to query the Spotify API is spotifyr.

packages <- c('spotifyr','lubridate','ggplot2','dplyr','tidytext','stringr','tidyr','viridis','wordcloud', "tm",'forcats','fmsb','scales','radarchart','qdap','knitr','geniusr','tidyverse','plotly')
lapply(packages,require,character.only=T)
rm(packages)

The package requieres a Client ID and a Client Secret to query the API. To do so, the user must have a premium account in order to create a developers account. The proccess could be done here. Once this process is done, you can pull spotify access token into R with get_spotify_access_token(). Note that you could pass your ID and secret in order to set your credentials into System Environment. For more information on the packages reference to Charlie Thompson’s spotifyr Github repository.

Sys.setenv(SPOTIFY_CLIENT_ID = 'xxxxxxxxxxxxxxxxxxxxx')
Sys.setenv(SPOTIFY_CLIENT_SECRET = 'xxxxxxxxxxxxxxxxxxxxx')

access_token <- get_spotify_access_token()

To get Pearl Jam’s songs audio features we use the function get_artist_audio_features(). This functions queries the Spotify API and returns information on several characteristics such as: danceability, energy, instrumentalness, valene, explicit content, track name, track album, etc. Now, I’ll only keep songs featuring in the 11 albums. The reason is to eliminate live performances and covers and focus on self-written songs. Lastly we verify there are no repeated sing in the data set.

albums <- c("Riot Act", "Ten", "Yield", "Gigaton", "Backspacer", "Vs.", "Pearl Jam", "No Code", "Vitalogy", "Binaural", "Lightning Bolt")
pj <- pj[pj$album_name %in% albums,]
pj <- mutate(pj, dupli=ifelse(duplicated(pj$track_name)==T,1,0))
pj <- subset(pj,dupli == 0)
head(pj,5) %>% select(track_name, album_name,artist_name,album_release_date,danceability,instrumentalness,energy,valence, key_name,mode_name) %>%  kable(format = "simple", col.names = str_to_title(gsub("[_]", " ", colnames(.))),align = 'lccccccccc',caption = "An example table caption.",digits = 3)
An example table caption.
Track Name Album Name Artist Name Album Release Date Danceability Instrumentalness Energy Valence Key Name Mode Name
retrograde Gigaton Pearl Jam 2020-03-27 0.457 0.000 0.616 0.277 G# major
johnny guitar Backspacer Pearl Jam 2009-09-19 0.549 0.000 0.921 0.825 D major
just breathe Backspacer Pearl Jam 2009-09-19 0.473 0.000 0.348 0.283 C major
immortality - remastered Vitalogy Pearl Jam 1994-11-22 0.633 0.007 0.543 0.118 D major
daughter (remastered) Vs. Pearl Jam 1993-10-19 0.615 0.004 0.702 0.734 G major

Lyrics: Genius API

As for Spotify’s API, the Genius API requieres a developers account in order to query information. To authenticate the information the user must: 1. Create a Genius API client here, 2. generate a client access token form the API Clients Page and 3. set your credential in the System environment variable GENIUS_API_TOKE calling the function genius_token(). Now, in order to fecth the lyrics for each song I created a loop that goes trhough every song in the data set and retrieves the lyrics in a single vector and then adds it to the create variable lyrics2.

pj <- mutate(pj, lyrics2 = "")
for (element in (1:nrow(pj))) {
  
  # I created the loop with two cicles in it in order to double check all the songs 
  # get their corresponding lyrics. Note that the loop isolates each song and
  # retrieves the information with the function et_lyrics_search()
  
  title <- str_to_title(pj$track_name[element]) 
  print(title)
  lyrics <- get_lyrics_search(artist_name = "Pearl Jam",
                              song_title = title)
  if (nrow(lyrics)!=0) {
    # I optedto reduce the dimensions of the retrieved data set to  one observation.
    # Now I save the first line and add the rest of the lines of the song
  lyrics2 <- ""
    for (piece in (1:nrow(lyrics))) {
    if (piece ==1) {
      lyrics2 <- lyrics$line[piece]
    }
    else{
      lyrics2 <- paste(lyrics2, lyrics$line[piece], collapse = " ")
    }
    print(title)
    print(lyrics2)
    }
  }
  
  # If any song had any problem with querying the lyrics the second part of the loop
  # repeats the procces to guarantee that all songs are assinged to their lyrics.
  
  if (nrow(lyrics)==0) {
    lyrics <- get_lyrics_search(artist_name = "Pearl Jam",
                                song_title = title)
    lyrics2 <- ""
    for (piece in (1:nrow(lyrics))) {
      if (piece ==1) {
        lyrics2 <- lyrics$line[piece]
      }
      else{
        lyrics2 <- paste(lyrics2, lyrics$line[piece], collapse = " ")
      }
      print(title)
      print(lyrics2)
    }
  }
  
  # Finally the song is added to the original data
  
  pj$lyrics2[element] <- lyrics2
}

Our data set now contains lyrics to all the 146 songs in the 11 albums. A glimpse to my top two Pearl Jam songs (according to spotify rankings) Black and Even flow:

songs <- c('Black', 'Even Flow')
pj[pj$track_name %in% songs,] %>% select(artist_name, album_name, track_name, lyrics) %>% 
  kable(format = "simple",col.names = str_to_title(gsub("[_]", " ", colnames(.))),align = 'lccccccccc')
Artist Name Album Name Track Name Lyrics
18 Pearl Jam Ten Even Flow freezin’ rests his head on a pillow made of concrete again oh feelin’ maybe he will see a little better set of days ooh yeah oh hand out faces that he sees time again ain’t that familiar oh yeah oh dark grin he can’t help when he’s happy he looks insane hm yeah even flow thoughts arrive like butterflies oh he don’t know so he chases them away oh someday yet he will begin his life again life again life again kneelin’ looking through the paper though he doesn’t know to read oh yeah oh prayin’ now to something that has never showed him anything oh feelin’ understands the weather of the winters on its way oh ceilings few and far between all the legal halls of shame hey even flow thoughts arrive like butterflies oh he don’t know so he chases them away oh someday yet he will begin his life again ah whispering hands gently lead him away him away him away yeah woo ah yeah fuck it up interlude hey man you got a dollar come on just some spare change man i know you got well god bless you man god bless you even flow thoughts arrive like butterflies oh he don’t know so he chases them away oh someday yet he will begin his life again oh whispering hands gently lead him away him away him away yeah woo ah yeah
19 Pearl Jam Ten Black hey hey yeah uh sheets of empty canvas untouched sheets of clay were laid spread out before me as her body once did all five horizons revolved around her soul as the earth to the sun now the air i tasted and breathed has taken a turn mm and all i taught her was everything mm i know she gave me all that she wore and now my bitter hands chafe beneath the clouds of what was everything oh the pictures have all been washed in black tattooed everything i take a walk outside i’m surrounded by some kids at play i can feel their laughter so why do i sear mm and twisted thoughts that spin ’round my head i’m spinning oh i’m spinning how quick the sun can drop away and now my bitter hands cradle broken glass of what was everything all the pictures have all been washed in black tattooed everything all the love gone bad turned my world to black tattooed all i see all that i am all i’ll be yeah mm mhm oooh i know someday you’ll have a beautiful life i know you’ll be a star in somebody else’s sky but why why why can’t it be oh can’t it be mine ooh ah yeah ah ooh doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo doodoo-doo-doo-doodoodoo ooh ooh ooh doodoo-doo-doo-doodoodoo ooh

Finally, we have to take into account instumental songs. Even though Pearl Jam doesn’t have many instrumental songs 3 cases need to be adressed. these are Arc, Aya Davanita and Cready Stomp. I proced then to assing a missing value to these songs in order to implement the followong analysis.

songs <- c("Arc","Aya Davanita - Remastered","Cready Stomp - Bonus Track")
pj[pj$track_name %in% songs,grep('lyrics', colnames(pj))]
## [1] "awoohaye davanitaawoohawoohajahoohjahooh repeat awoohaye davanitaawoohawooha x"
## [2] "vocal"                                                                         
## [3] "intrumental"
pj[pj$track_name %in% songs,grep('lyrics', colnames(pj))] <- NA

Data exploration

Tokens & data wrangling

The dataset is almost ready for use. I now execute some few data wrangling steps in order to have all the information needed. I use the package tm in order to remove punctuation, stop words and stemming. I begin by compiling all lyrics and create a corpus using the function VectorSource to read it a s a document and then pass the documents through the Corpus to create the final corpus. Note that all the document transformation of the document are done through the funciton tm_map, applying a function to all elements of the document. The process I follow is: 1) transform all upper-case letter to lower-case; 2) remove all punctionation; 3) remove English stop words; and 4) stem all the white spaces.

lyrics <- Corpus(VectorSource(pj$lyrics))
lyrics <- tm_map(lyrics, content_transformer(tolower))
lyrics <- tm_map(lyrics, removePunctuation)
lyrics <- tm_map(lyrics, removeWords, stopwords("english"))
lyrics <- tm_map(lyrics, stripWhitespace)
lyrics <- lyrics %>% unlist()
pj$lyrics <- as.character(lyrics[1:nrow(pj)])
pj$lyrics <- str_trim(pj$lyrics)

After procesing the lyrics there’s still some special cases that need to be taken into account ir order to prevent bias in the results. First, word contractions need to be addressed. As I removed all punctuation before, some contractions such as she’s will be now shes and are not taken as stop words by the function tm_map. Other cases are rythmitic vocals. Take Black as an example. The last minute of the song Eddie goes on like doo doo doo doo doo doo doo. In order to prevent biased results I ommit all rythmitic vocals and replace the contractions by their respective joint words.

pj$lyrics <- str_replace_all(pj$lyrics, 'bottomoh', ' bottom oh ')
pj$lyrics <- str_replace_all(pj$lyrics, ' heyim ', ' hey I am ')
pj$lyrics <- str_replace_all(pj$lyrics, ' deepoh ', ' deep oh ')
pj$lyrics <- str_replace_all(pj$lyrics, ' butterfliesdont ', ' butterflies do not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' awaysomeday ', ' away someday ')
pj$lyrics <- str_replace_all(pj$lyrics, ' risingnext ', ' rising next ')
pj$lyrics <- str_replace_all(pj$lyrics, ' uhohoh ', ' oh ')
pj$lyrics <- str_replace_all(pj$lyrics, ' angellest ', ' angel lets ')
pj$lyrics <- str_replace_all(pj$lyrics, ' doodoodoodoodoodoodoo ', '')
pj$lyrics <- str_replace_all(pj$lyrics, ' yeah ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' yeah', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ooh ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' oh ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ah ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' hm ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ye ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ay ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' yeh ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ya ', 'you')
pj$lyrics <- str_replace_all(pj$lyrics, ' mm ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' interlude ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' woo ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' mhm ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' oooh ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ooooh ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' hey ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' uh ', ' ')
pj$lyrics <- str_replace_all(pj$lyrics, ' youll ', ' you will ')
pj$lyrics <- str_replace_all(pj$lyrics, ' cant ', ' can not ')
pj$lyrics <- str_replace_all(pj$lyrics, 'cant ', ' can not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' im ', ' I am ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ill ', ' I will ')
pj$lyrics <- str_replace_all(pj$lyrics, ' didnt ', ' did not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' dont ', ' do not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' hes ', ' he is ')
pj$lyrics <- str_replace_all(pj$lyrics, ' uhhuh ', '')
pj$lyrics <- str_replace_all(pj$lyrics, ' its' , '')
pj$lyrics <- str_replace_all(pj$lyrics, ' id ', ' I would ')
pj$lyrics <- str_replace_all(pj$lyrics, ' youre ', ' you are ')
pj$lyrics <- str_replace_all(pj$lyrics, ' youve ', ' you have ')
pj$lyrics <- str_replace_all(pj$lyrics, ' youd ', ' you would ')
pj$lyrics <- str_replace_all(pj$lyrics, ' theres ', ' there is ')
pj$lyrics <- str_replace_all(pj$lyrics, ' theyll ', ' they will ')
pj$lyrics <- str_replace_all(pj$lyrics, ' whats ', ' what is ')
pj$lyrics <- str_replace_all(pj$lyrics, ' doesnt ', ' does not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' ive ', ' I have ')
pj$lyrics <- str_replace_all(pj$lyrics, ' hadnt ', ' had not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' wouldnt ', ' would not ')
pj$lyrics <- str_replace_all(pj$lyrics, ' til ',' until ')
pj$lyrics <- str_replace_all(pj$lyrics, ' wouldve ', ' would have ')
pj$lyrics <- str_replace_all(pj$lyrics, ' shes ', ' she is ')
pj$lyrics <- str_replace_all(pj$lyrics, ' thats ', ' that is ')

One last step into our final dataset is word sentiment. I then turn the data into a tidy format using the package tidytext. I use the function unnest_tokens in order to split the lyrics into indivudual words. the function get_sentiments is usedto obtain the sentiments lexicon in a tidy format. The lexicon used is NCR Word-Emotion Association Lexicon. This lexicon lists English words and matches their associations with eight basic emotions (anger, fear, anticipation, trust, surprise, sadness, joy, and disgust) and two sentiments (negative and positive). Further information could be found in the official web page. With the sentiments matched I’m able to count the number of words per emotion and sentiment.

pearl_songs <- pj %>% unnest_tokens(word, lyrics) # Separate the lyrics into single words
cleaned_pearl <- pearl_songs %>% anti_join(stop_words) # Eliminating stop words
nrc <- get_sentiments(lexicon = "nrc") # Categorical words sentiments

pearl_sentiment <- cleaned_pearl %>%
  inner_join(nrc,by = c('word')) %>% # Merging the word sentiment data with the words dataset
  count(track_name, sentiment) %>% # Counting the number of words per sentiment
  spread(sentiment, n, fill = 0) # Reshaping the data from observations into columns

columns <- c(grep('album_name', colnames(pj)),
             grep('track_name', colnames(pj)))

pearl_sentiment <- inner_join(x = pearl_sentiment, y = pj[,columns], by = "track_name")
pj <- inner_join(pj, pearl_sentiment)

Gloom Index

With the final dataset I’m able to do some sort of analysis to Pearl Jam’s discography. At first hand I was interested in finding some metric of sadness in a musical context. One of the most interesting analysis taking this into account is the Gloom Index developed by Charlie Thompson. Here the author uses the information on the valence of the song, the percentage of sad songs and the lyrical density of the song. In terms of valence, Spotify uses a wide variety of inputs to determine weather a songs sound happy or not. With this in mind sad songs have a lower valence score and happy songs have high valence. Here’s a preview of some of Pearl Jam’s saddest songs according this measure:

pj %>% group_by(track_name) %>% summarise(valence = mean(valence)) %>% arrange(valence) %>% head(10) %>% kable(format = "simple", col.names = str_to_title(gsub("[_]", " ", colnames(.))),align = 'lc',caption = "Top ten saddest Pearl Jam songs - Valence score",digits = 3)
## `summarise()` ungrouping output (override with `.groups` argument)
Top ten saddest Pearl Jam songs - Valence score
Track Name Valence
Nothing As It Seems 0.044
Of The Girl 0.049
Sometimes 0.062
Release 0.064
All Those Yesterdays 0.068
Inside Job 0.074
I’m Open 0.098
Wishlist 0.101
Crazy Mary (Remastered) 0.104
Wasted Reprise 0.104

Originally the index takes the following form:

\[Gloom\;Index = \frac{(1-valence) + percentage\_sad(1+lyrical\_density)}{2}\] Now, noting that the lyrical density migth be misleading I turn to other measure of lyrical density. Longer songs might have more repeated lyrics than shorter songs. This can be either by more choruses or bridges, but the results might be wrong for this reason. Accounting for this problem a cleaner metric for lyrical density is the ratio of disticnt words and total words used. \[Glomm\; Index = \frac{(1-valence)+percentage\_sad(1+distinct\_percentage)}{2}\]

Where

\[distinct\_percentage = \frac{\# distinct \;words}{\# total words}\]

Now, having this information how can this index be interpreted? We need to understand how gloom moves along the different inputs. First, valence shows higher values for happy songs whilst low values for sad songs. Now, by subtracting the valence, a song with lower valence will have a higher index score. In other words, valence has an inverse relationship with the gloom index. Now, turbulent words and distinct words percentage logically move in the same direction of the gloom index. I can now say that higher values show sadder songs, while lower values represent happier songs. Note that compared to Charlie’s Radiohead analysis my index is interpreted in a completely different way. The main reason is because Charlie rescales his index in order to represent happy songs with higher values. Now, the interpretation of the results are analogous, the only difference are the scale in which they are presented.

pj <- pj %>% unnest_tokens(word, lyrics) %>%
  group_by(track_name) %>% summarise(distinct_words = n_distinct(word)) %>% 
  inner_join(pj)
## `summarise()` ungrouping output (override with `.groups` argument)
## Joining, by = "track_name"
pj <- mutate(pj, words = sapply(strsplit(pj$lyrics, " "), length))
pj <- mutate(pj, seconds = duration_ms/1000)
pj <- mutate(pj, words_per_second = words/seconds)
pj <- mutate(pj, sad_percentage = sadness/distinct_words)
pj <- mutate(pj, dist_per = (distinct_words/words))
pj <- mutate(pj, index = ((1-valence)+sad_percentage*(1+dist_per))/2)

I can now vizualize different information I have gathered along the document. First, we can see the saddest songs according to the Gloom Index.

pj %>% group_by(track_name,album_name) %>% 
  summarise(index = mean(index),
            valence = mean(valence),
            `turbulent words` = mean(sad_percentage),
            `distinct percentage words` = mean(dist_per)) %>% arrange(desc(index)) %>% head(10) %>% kable(format = "simple", col.names = str_to_title(gsub("[_]", " ", colnames(.))),align = 'lccccc',caption = "Top ten saddest Pearl Jam songs - Gloom Index",digits = 3)
## `summarise()` regrouping output by 'track_name' (override with `.groups` argument)
Top ten saddest Pearl Jam songs - Gloom Index
Track Name Album Name Index Valence Turbulent Words Distinct Percentage Words
Spin The Black Circle - Remastered Vitalogy 0.774 0.141 0.525 0.312
Comatose Pearl Jam 0.754 0.221 0.500 0.460
Red Bar Yield 0.733 0.700 0.667 0.750
Deep Ten 0.606 0.250 0.326 0.422
Inside Job Pearl Jam 0.543 0.074 0.097 0.653
Of The Girl Binaural 0.527 0.049 0.061 0.717
Love Boat Captain Riot Act 0.522 0.176 0.137 0.605
Once Ten 0.518 0.211 0.151 0.631
Release Ten 0.514 0.064 0.057 0.603
Sometimes No Code 0.514 0.062 0.050 0.784

We have now the most depressing Pearl Jam song to date: Spin the Black Circle. But how can it be? Anyone who have heard the rigth ammount of their songs could argue in favor of Release or All those yesterdays, or even Black, but remember that this is a data driven measure. Spin the Black Circle actually has a rather low valence score (meaning is a sad song), ranking 19th with 0.141. But the percentage of sad words is the second highest of all songs, behind Red Bar (which repeats seven times) wih a percentage of sad word of 52%. If the ranking seems odd listen to the songs and see it for yourself.

To see how sadness or gloom has evolved across time, is posible to average the index per album and see the dynamic. This is the ranking for the saddest albums:

pj %>% group_by(album_name) %>% 
  summarise(index = mean(index),
            valence = mean(valence),
            `sad words` = mean(sad_percentage),
            `distinct percentage words` = mean(dist_per)) %>% arrange(desc(index)) %>% head(12) %>% kable(format = "simple", col.names = str_to_title(gsub("[_]", " ", colnames(.))),align = 'lccccc',caption = "Saddest Pearl Jam albums - Gloom Index",digits = 3)
## `summarise()` ungrouping output (override with `.groups` argument)
Saddest Pearl Jam albums - Gloom Index
Album Name Index Valence Sad Words Distinct Percentage Words
Ten 0.432 0.244 0.071 0.561
Yield 0.399 0.332 0.075 0.642
Vitalogy 0.394 0.311 0.068 0.545
Pearl Jam 0.379 0.408 0.105 0.596
No Code 0.343 0.360 0.028 0.632
Riot Act 0.336 0.430 0.064 0.644
Gigaton 0.325 0.484 0.082 0.625
Vs. 0.309 0.445 0.044 0.477
Binaural 0.293 0.489 0.045 0.704
Lightning Bolt 0.272 0.577 0.072 0.668
Backspacer 0.251 0.604 0.069 0.546

Now, it is posible to include both results from the last two tables in one graph in order to compare the results. Each point in the graph represents a songs, and for each song theres a gloom index score. The black dots represent the average score for each album. It is improtant to note that by the tim pearl jam songs seem to be growing less sad.

pal <- c("turquoise4","navyblue","peru","goldenrod2","forestgreen","darkgray",
         "orange","magenta","lightslateblue","yellowgreen","mediumblue")

fig <- plot_ly(data = rank,
              x = ~album_name, y = ~average,type = 'scatter',mode = 'markers',
              marker = list(size = 10),
              color = ~album_name, colors = pal, span = I(1),stroke = I("black"),
              text = ~paste("Gloom Index score: ", round(average,3), '<br>Track:', track_name))

fig <- fig %>% add_trace(y = ~gloom_index,mode = 'lines+markers',type = 'scatter',name = 'Album Average',
                      color = I('black'),stroke = I("black"),marker = list(size = 10),
                      text = ~paste("Album average valence:", round(gloom_index,3),                                              '<br>Album:',album_name))

fig %>% layout(xaxis = list(zeroline = T, title ="Album Name"),
               yaxis = list(hoverformat = '.3f', title = 'Gloom Index'),
               showlegend = F)
## Warning: `arrange_()` is deprecated as of dplyr 0.7.0.
## Please use `arrange()` instead.
## See vignette('programming') for more help
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.

With this graph we can conclude some things. First, the saddest Pearl Jam album to date is Ten, followed by Yield and Vitalogy. On the other hand, the happiest albums being Backspacer and Lightning Bolt and the tops sad songs being Parting ways and Supersonic.

Word counts by album and song

With the dataset I’m able to do some extra exploration. For example, how many words does each album have in average? How many words per second? What’s the wordiest song and album? In order to answer this question is important to rely in an important word count statistic. For this matter i will use the count of distictive words used in the song. But, why this statistic? I considered distinct words in order to avoid reptetiveness. For example, in analizing Deep, you can hear about 7 times can’t touch the bottom. In doing so we are not being guided by the repetiveness of the song, but the different words used.

pj %>% group_by(track_name,album_name) %>% summarise(distinct_words = mean(distinct_words),
                                                     word_per_song = mean(words),
                                                     words_per_second = mean(words_per_second)) %>%              arrange(desc(distinct_words)) %>% head(10) %>%
  kable(format = "simple", col.names = str_to_title(gsub("[_]", " ", colnames(.))),align = 'lcccc',caption = "Pearl Jam word count by song",digits = 3)
## `summarise()` regrouping output by 'track_name' (override with `.groups` argument)
Pearl Jam word count by song
Track Name Album Name Distinct Words Word Per Song Words Per Second
Seven O’clock Gigaton 154 187 0.500
Who Ever Said Gigaton 131 187 0.600
Stupidmop - Remastered Vitalogy 128 444 1.000
My Father’s Son Lightning Bolt 119 176 0.951
River Cross Gigaton 105 161 0.454
Comes Then Goes Gigaton 104 142 0.392
Never Destination Gigaton 104 187 0.726
Satan’s Bed - Remastered Vitalogy 103 173 0.844
Lightning Bolt Lightning Bolt 97 119 0.470
Crazy Mary (Remastered) Vs. 96 155 0.457

Wordclouds

At this point I’am able to use the filtered data into wordclouds by using the word counts for each song. By doing so the main objective is to vizualize the pricipal words used in each song by adding the total words used in each song across albums. I use the packages wordcloud and tm. I then follow to use the functions wordcloud(from wordcloud) and DocumentTermMatrix, Corpus and VectorSource (from tm). I plot the top 100 words selected by the word counts in each album (aggreated by the sum of each words count by song)

A small caveat in this section: Word counts do not account for song repetiiveness. So word usage might be biased in terms of repetition within each song and album. Section 2.6 (Term frequency Inverse Document Frequency (TF-IDF)) takes this problem into account by using a measure of the importance of each word in teach song.

Ten

Vs.

Vitalogy

No Code

Yield

Binaural

Riot Act

Pearl Jam

Backspacer

Lighthing Bolt

Gigaton

Vocabulary diversity

pj %>% group_by(album_name,track_name) %>% summarise(number_words = mean(distinct_words)) %>% 
  ggplot(data = ., aes(x = factor(album_name),y = number_words)) +geom_violin(alpha = 0.7, color = 'black', size = 0.2)+
  geom_jitter(aes(size = number_words),height = 0, width = 0.1, alpha =0.2) + geom_boxplot(aes(fill = album_name), alpha = 0.6) +
  labs(title = "Lexical Diversity - Vocabulary", x = "", y = 'Distinct words count') + theme_bw() + 
  theme(plot.title = element_text(hjust = 0.5, size = 10),
        axis.title = element_text(size = 8),
        axis.text = element_text(size = 7),
        legend.title  = element_text(size = 8),
        legend.position = "bottom",
        panel.grid.major = element_line(size = 0.4)) + guides(fill = F) + scale_size('Number of words')
## `summarise()` regrouping output by 'album_name' (override with `.groups` argument)

Term Frequency Inverse Document Frequency (TF-IDF)

album_levels1 <- c("Ten", "Vs.", "Vitalogy", "No Code", "Yield", "Binaural")
album_levels2 <- c("Riot Act", "Pearl Jam", "Backspacer", "Lightning Bolt", "Gigaton")

frequency[frequency$album_name %in% album_levels1,] %>% group_by(album_name) %>% 
  slice_max(tf_idf, n = 15) %>% ungroup() %>%
  ggplot(aes(tf_idf,fct_reorder(word, tf_idf), fill = album_name)) +
  geom_col(show.legend = F) + facet_wrap(~album_name, ncol = 3, scales = "free") +
  labs(x = "tf-idf", y = NULL)+theme(axis.text = element_text(size = 7.5))

frequency[frequency$album_name %in% album_levels2,] %>% group_by(album_name) %>% 
  slice_max(tf_idf, n = 15) %>% ungroup() %>%
  ggplot(aes(tf_idf,fct_reorder(word, tf_idf), fill = album_name)) +
  geom_col(show.legend = F) + facet_wrap(~album_name, ncol = 3, scales = "free") +
  labs(x = "tf-idf", y = NULL)+theme(axis.text = element_text(size = 7.5))

Sentiment Analysis and Natural Language Processing

NCR Sentiment

pj$album_name <- factor(pj$album_name, levels = album_levels)
pj[pj$album_name %in% album_levels1,] %>% group_by(album_name) %>% summarise(fear = sum(fear),
                                           anger = sum(anger),
                                           anticipation = sum(anticipation),
                                           disgust = sum(disgust),
                                           joy = sum(joy),
                                           # negative = sum(negative),
                                           # positive = sum(positive),
                                           sadness = sum(sadness),
                                           surprise = sum(surprise),
                                           trust = sum(trust)) %>% 
  reshape2::melt(id.vars = c('album_name'), value.name = 'sentiment') %>% 
  ggplot(aes(x = variable, y = sentiment, fill = sentiment)) + geom_bar(stat = 'identity') + coord_flip()+
  facet_wrap(~album_name, ncol = 3, scales = "free") + theme_bw() + scale_fill_viridis() + 
  labs(y = "Word count", x = "NCR Sentiment") + theme(legend.position = 'none')
## `summarise()` ungrouping output (override with `.groups` argument)

pj[pj$album_name %in% album_levels2,] %>% group_by(album_name) %>% summarise(fear = sum(fear),
                                           anger = sum(anger),
                                           anticipation = sum(anticipation),
                                           disgust = sum(disgust),
                                           joy = sum(joy),
                                           # negative = sum(negative),
                                           # positive = sum(positive),
                                           sadness = sum(sadness),
                                           surprise = sum(surprise),
                                           trust = sum(trust)) %>% 
  reshape2::melt(id.vars = c('album_name'), value.name = 'sentiment') %>% 
  ggplot(aes(x = variable, y = sentiment, fill = sentiment)) + geom_bar(stat = 'identity') + coord_flip()+
  facet_wrap(~album_name, ncol = 3, scales = "free") + theme_bw() + scale_fill_viridis() + 
  labs(y = "Word count", x = "NCR Sentiment") + theme(legend.position = 'none')
## `summarise()` ungrouping output (override with `.groups` argument)

Radarplots

radar <- pj[,c(grep('album_name', colnames(pj)),
                grep('fear', colnames(pj)),
                grep('anger', colnames(pj)),
                grep('anticipation', colnames(pj)),
                grep('disgust', colnames(pj)),
                grep('sadness', colnames(pj)))] %>% 
  group_by(album_name) %>% summarise(fear = mean(fear),
                                     anger = mean(anger),
                                     anticipation = mean(anticipation),
                                     disgust = mean(disgust),
                                     sadness = mean(sadness))
## `summarise()` ungrouping output (override with `.groups` argument)
colnames(radar) <- str_to_title(colnames(radar))
chartJSRadar(radar)
radar <- pj[,c(grep('album_name', colnames(pj)),
                grep('joy', colnames(pj)),
                grep('surprise', colnames(pj)),
                grep('trust', colnames(pj)))] %>% 
  group_by(album_name) %>% summarise(joy = mean(joy),
                                     surprise = mean(surprise),
                                     trust = mean(trust)
  )
## `summarise()` ungrouping output (override with `.groups` argument)
colnames(radar) <- str_to_title(colnames(radar))
chartJSRadar(radar)
radar <- pj[,c(grep('album_name', colnames(pj)),
               grep('positive', colnames(pj)),
               grep('negative', colnames(pj)))] %>% 
  group_by(album_name) %>% summarise(positive = mean(positive),
                                     negative = mean(negative)
  )
## `summarise()` ungrouping output (override with `.groups` argument)
colnames(radar) <- str_to_title(colnames(radar))
chartJSRadar(radar)

Bi-grams and tri-grams

bigrams <-  pj[,c(grep('track_name', colnames(pj)),
                   grep('album_name', colnames(pj)),
                   grep('lyrics', colnames(pj)))] %>%
            unnest_tokens(bigram, lyrics, token = "ngrams", n = 2) %>% 
            separate(bigram, c("word1", "word2"), sep = " ") %>% 
            filter(!word1 %in% stop_words$word) %>%
            filter(!word2 %in% stop_words$word) %>% 
            filter(word1 != word2) %>% 
            unite(bigram, word1, word2, sep = " ") %>% 
            inner_join(pj)  %>% 
            count(bigram, album_name, sort = TRUE) %>%   
            group_by(album_name) %>% 
            slice(seq_len(10)) %>% 
            ungroup() %>% arrange(album_name,n)
## Joining, by = c("track_name", "album_name")
bigrams$album_name <- factor(bigrams$album_name, levels = album_levels)

ggplot(data = bigrams[bigrams$album_name %in% album_levels1,], aes(x = bigram, y = n, fill = album_name))+
geom_col(show.legend = F) + coord_flip() + theme_bw()+ labs(y = 'Number of repetitions', x ='Bigram')+
facet_wrap(~album_name, scales = "free_y") 

ggplot(data = bigrams[bigrams$album_name %in% album_levels2,], aes(x = bigram, y = n, fill = album_name))+
geom_col(show.legend = F) + coord_flip() + theme_bw()+ labs(y = 'Number of repetitions', x ='Bigram')+
facet_wrap(~album_name, scales = "free_y") 

LS0tCmF1dGhvcjogIkpvcmdlIEx1aXMgT2Nob2EiCnRpdGxlOiAiUGVhcmwgSmFtIEFuYWx5c2lzIGluIFIiCmRhdGU6ICIxLzEyLzIwMjEiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQogICAgIyB0aGVtZTogY29zbW8KICAgIHRoZW1lOiBsdW1lbgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCnJpZ2h0OgogIC0gdGV4dDogR2l0SHViCiAgICBocmVmOiBodHRwczovL2dpdGh1Yi5jb20KLS0tCgpgYGB7ciAsIGluY2x1ZGU9Rn0KIyBwaiA8LSByZWFkUkRTKGZpbGUgPSAnRGF0YS9wZWFybC5SRFMnKQpwaiA8LSByZWFkUkRTKGZpbGUgPSAnRGF0YS9wZWFybCBqYW0gMi5SRFMnKQpyb3dzIDwtIHNhbXBsZShucm93KHBqKSkKcGogPC0gcGpbcm93cyxdCmBgYAoKIyMgTXVzaWNhbCBhbmQgbHlyaWNhbCBhbmFseXNpcyBvZiBQZWFybCBKYW0ncyBzb25ncwoKVGhpcyByZXBvc2l0b3J5IGNvbXByaXNlcyBhIG11c2ljYWwgYW5kIGx5cmljYWwgYW5hbHlzaXMgb2YgUGVhcmwgSmFtJ3Mgc29uZ3MuIEkgdXNlIGRhdGEgZnJvbSBTcG90aWZ5J3MgYW5kIEdlbml1cydzIEFQSXMuIEkgdXNlIHNjcmlwdHMgdG8gcXVlcnkgaW5mb3JtYXRpb24gb24gdGhlIG11c2ljYWwgcHJvcGV0eSBvZiBhbGwgb2YgdGhlIDExIFBlYXJsIEphbSBhbGJ1bXMuIEkgbGF0ZXIgdXNlIGEgc2NyaXB0IHRvIHNjcmFwZSB0aGUgbHlyeWNzIHRvIHNldmVyYWwgc29uZ3MgYW5kIGZpbmFsbHkgdXNlIHRoZSBHZW5pdXMgQVBJIHRvIGRvd25sb2FkIHRoZSByZW1haW5pbmcuIFJlbGF0ZWQgd29ya3MgaW5jbHVkZSBbS2VuZHJpY2sgTGFtYXIgc2VudGltZW50IGFuYWx5c2lzXShodHRwczovL2dpdGh1Yi5jb20vZGF2aWRrbGFpbmcva2VuZHJpY2svYmxvYi9tYXN0ZXIvUkVBRE1FLm1kKSwgW0dsb29tIEluZGV4XShodHRwczovL3d3dy5yY2hhcmxpZS5jb20vYmxvZy9maXR0ZXItaGFwcGllci8pIHRvIGZpbmQgUmFkaW9oZWFkJ3MgbW9zdCBkZXByZXNzaW5nIHNvbmcgYnkgW0NoYXJsaWUgVGhvbXBzb25dKGh0dHBzOi8vd3d3LnJjaGFybGllLmNvbSksIFtCb2IgRHlsYW4gbHlyaWNhbCBhbmFseXNpc10oaHR0cHM6Ly9ycHVicy5jb20vcGF1bF9yZWluZXJzLzQwNjM1OSkgYnkgUGF1bCBSZWluZXJzLCBbdGlkeSBzZW50aW1lbnQgYW5hbHlzaXNdKGh0dHBzOi8vd3d3LmRhdGFjYW1wLmNvbS9jb21tdW5pdHkvdHV0b3JpYWxzL3NlbnRpbWVudC1hbmFseXNpcy1SKSBvbiBQcmluY2UncyBtdXNpYyBieSBEZWJiaWUgTGlza2UgYW5kIFtNdXNpY2FsIEx5cmljcyBBbmFseXNpc10oaHR0cHM6Ly9ycHVicy5jb20vQnJlZU1jTGVubmFuL211c2ljX2x5cmljX2FuYWx5c2lzKSBvbiBzZXZlcmFsIGFydGlzdHMgYnkgQnJlZSBNY0xlbm5hbi4KClRoZSByZXBvIGlzIG9yZ2FuaXplZCBhcyBmb2xsb3dzOgoKCiogKipEYXRhIEFzc2Vzc21lbnQqKgogICsgKipJbnRlbGxlY3R1YWwgUHJvcGVydHkgKENvcHlyaWd0aHMpKioKICArICoqU29uZ3Mgc2VsZWN0aW9uOiBTcG90aWZ5IEFQSSoqCiAgKyAqKkx5cmljczogR2VuaXVzIEFQSSoqCgoqICoqRGF0YSBleHBsb3JhdGlvbioqCiAgKyAqKlRva2VucyAmIGRhdGEgd3JhbmdsaW5nKioKICArICoqR2xvb20gSW5kZXgqKgogICsgKipXb3JkIGNvdW50cyBieSBhbGJ1bSBhbmQgc29uZyoqCiAgKyAqKldvcmRjbG91ZHMqKgogICsgKipWb2NhYnVsYXJ5IGRpdmVyc2l0eSoqCiAgKyAqKlRlcm0gRnJlcXVlbmN5IEludmVyc2UgRG9jdW1lbnQgRnJlcXVlbmN5IChURi1JREYpKioKCiogKipTZW50aW1lbnQgQW5hbHlzaXMgYW5kIE5hdHVyYWwgTGFuZ3VhZ2UgUHJvY2Vzc2luZyoqCiAgKyAqKk5DUiBTZW50aW1lbnQqKgogICsgKipCaS1ncmFtcyBhbmQgdHJpLWdyYW1zKioKICAKIyBEYXRhIEFzc2Vzc21lbnQKIyMgSW50ZWxsZWN0dWFsIFByb3BlcnR5IChDb3B5cmlndGhzKQoKSSB3b3VsZCBsaWtlIHRvIGFja25vd2xlZGdlIHRoYXQgZXZlcnkgc2luZ2xlIGNvbnRlbnQgZXhwb3NlZCBpbiB0aGlzIHJlcG9zaXRvcnkgaXMgYmFzZWQgb24gcHJvdGVjdGVkIHNvbmdzLiBBbGwgdGhlIHJpZ3RocyBvZiB0aGUgZGF0YSB1c2VkIGNvbWUgZnJvbSB0aGUgU3BvdGlmeSBBUEksIEdlbml1cyBBUEksIGJ1dCBtYWlubHkgdGhlIHNvbndyaXRlcnMgYW5kIGNvbXBvc2VycyBvZiB0aGUgc29uZ3MuIEluIG5vIHdheSBpdCBpcyBpbnRlbnRlZCB0byBtYWtlIGl0IGFzIG15IG93bi4gQWxsIHRoZSBtaXN0YWtlcyBtYWRlIGFyZSBteSBvd24gYW5kIG5vIG9uZSBlbHNlLgoKIyMgU29uZ3Mgc2VsZWN0aW9uOiBTcG90aWZ5IEFQSQoKSSBmaXJzdCBhc2luZyBhbGwgdGhlIHBhY2thZ2VzIG5lZWRlZCBpbnRvIHRoZSB2ZWN0b3IgYHBhY2thZ2VzYC4gSW4gdGhpcyBzZWN0aW9uIHRoZSBpbXBvcnRhbnQgcGFja2FnZSB0byBxdWVyeSB0aGUgU3BvdGlmeSBBUEkgaXMgYHNwb3RpZnlyYC4KCmBgYHtyLCBldmFsPVQgLGluY2x1ZGU9Rn0KcGFja2FnZXMgPC0gYygnc3BvdGlmeXInLCdsdWJyaWRhdGUnLCdnZ3Bsb3QyJywnZHBseXInLCd0aWR5dGV4dCcsJ3N0cmluZ3InLCd0aWR5cicsJ3ZpcmlkaXMnLCd3b3JkY2xvdWQnLCAidG0iLCdmb3JjYXRzJywnZm1zYicsJ3NjYWxlcycsJ3JhZGFyY2hhcnQnLCdxZGFwJywna25pdHInLCdnZW5pdXNyJywndGlkeXZlcnNlJywncGxvdGx5JykKbGFwcGx5KHBhY2thZ2VzLHJlcXVpcmUsY2hhcmFjdGVyLm9ubHk9VCkKcm0ocGFja2FnZXMpCmBgYAoKYGBge3IsIGV2YWw9RiAsaW5jbHVkZT1UfQpwYWNrYWdlcyA8LSBjKCdzcG90aWZ5cicsJ2x1YnJpZGF0ZScsJ2dncGxvdDInLCdkcGx5cicsJ3RpZHl0ZXh0Jywnc3RyaW5ncicsJ3RpZHlyJywndmlyaWRpcycsJ3dvcmRjbG91ZCcsICJ0bSIsJ2ZvcmNhdHMnLCdmbXNiJywnc2NhbGVzJywncmFkYXJjaGFydCcsJ3FkYXAnLCdrbml0cicsJ2dlbml1c3InLCd0aWR5dmVyc2UnLCdwbG90bHknKQpsYXBwbHkocGFja2FnZXMscmVxdWlyZSxjaGFyYWN0ZXIub25seT1UKQpybShwYWNrYWdlcykKYGBgClRoZSBwYWNrYWdlIHJlcXVpZXJlcyBhIGBDbGllbnQgSURgIGFuZCBhIGBDbGllbnQgU2VjcmV0YCB0byBxdWVyeSB0aGUgQVBJLiBUbyBkbyBzbywgdGhlIHVzZXIgbXVzdCBoYXZlIGEgcHJlbWl1bSBhY2NvdW50IGluIG9yZGVyIHRvIGNyZWF0ZSBhIGRldmVsb3BlcnMgYWNjb3VudC4gVGhlIHByb2NjZXNzIGNvdWxkIGJlIGRvbmUgW2hlcmVdKGh0dHBzOi8vZGV2ZWxvcGVyLnNwb3RpZnkuY29tL2Rhc2hib2FyZC8pLiBPbmNlIHRoaXMgcHJvY2VzcyBpcyBkb25lLCB5b3UgY2FuIHB1bGwgc3BvdGlmeSBhY2Nlc3MgdG9rZW4gaW50byBSIHdpdGggYGdldF9zcG90aWZ5X2FjY2Vzc190b2tlbigpYC4gTm90ZSB0aGF0IHlvdSBjb3VsZCBwYXNzIHlvdXIgSUQgYW5kIHNlY3JldCBpbiBvcmRlciB0byBzZXQgeW91ciBjcmVkZW50aWFscyBpbnRvIFN5c3RlbSBFbnZpcm9ubWVudC4gRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhlIHBhY2thZ2VzIHJlZmVyZW5jZSB0byBDaGFybGllIFRob21wc29uJ3MgYHNwb3RpZnlyYCBHaXRodWIgW3JlcG9zaXRvcnldKGh0dHBzOi8vZ2l0aHViLmNvbS9jaGFybGllODYvc3BvdGlmeXIpLgoKYGBge3IsIGV2YWw9Rn0KU3lzLnNldGVudihTUE9USUZZX0NMSUVOVF9JRCA9ICd4eHh4eHh4eHh4eHh4eHh4eHh4eHgnKQpTeXMuc2V0ZW52KFNQT1RJRllfQ0xJRU5UX1NFQ1JFVCA9ICd4eHh4eHh4eHh4eHh4eHh4eHh4eHgnKQoKYWNjZXNzX3Rva2VuIDwtIGdldF9zcG90aWZ5X2FjY2Vzc190b2tlbigpCmBgYAoKVG8gZ2V0IFBlYXJsIEphbSdzIHNvbmdzIGF1ZGlvIGZlYXR1cmVzIHdlIHVzZSB0aGUgZnVuY3Rpb24gYGdldF9hcnRpc3RfYXVkaW9fZmVhdHVyZXMoKWAuIFRoaXMgZnVuY3Rpb25zIHF1ZXJpZXMgdGhlIFNwb3RpZnkgQVBJIGFuZCByZXR1cm5zIGluZm9ybWF0aW9uIG9uIHNldmVyYWwgY2hhcmFjdGVyaXN0aWNzIHN1Y2ggYXM6IGRhbmNlYWJpbGl0eSwgZW5lcmd5LCBpbnN0cnVtZW50YWxuZXNzLCB2YWxlbmUsIGV4cGxpY2l0IGNvbnRlbnQsIHRyYWNrIG5hbWUsIHRyYWNrIGFsYnVtLCBldGMuIE5vdywgSSdsbCBvbmx5IGtlZXAgc29uZ3MgZmVhdHVyaW5nIGluIHRoZSAxMSBhbGJ1bXMuIFRoZSByZWFzb24gaXMgdG8gZWxpbWluYXRlIGxpdmUgcGVyZm9ybWFuY2VzIGFuZCBjb3ZlcnMgYW5kIGZvY3VzIG9uIHNlbGYtd3JpdHRlbiBzb25ncy4gTGFzdGx5IHdlIHZlcmlmeSB0aGVyZSBhcmUgbm8gcmVwZWF0ZWQgc2luZyBpbiB0aGUgZGF0YSBzZXQuCgpgYGB7ciwgZXZhbD1UfQphbGJ1bXMgPC0gYygiUmlvdCBBY3QiLCAiVGVuIiwgIllpZWxkIiwgIkdpZ2F0b24iLCAiQmFja3NwYWNlciIsICJWcy4iLCAiUGVhcmwgSmFtIiwgIk5vIENvZGUiLCAiVml0YWxvZ3kiLCAiQmluYXVyYWwiLCAiTGlnaHRuaW5nIEJvbHQiKQpwaiA8LSBwaltwaiRhbGJ1bV9uYW1lICVpbiUgYWxidW1zLF0KcGogPC0gbXV0YXRlKHBqLCBkdXBsaT1pZmVsc2UoZHVwbGljYXRlZChwaiR0cmFja19uYW1lKT09VCwxLDApKQpwaiA8LSBzdWJzZXQocGosZHVwbGkgPT0gMCkKaGVhZChwaiw1KSAlPiUgc2VsZWN0KHRyYWNrX25hbWUsIGFsYnVtX25hbWUsYXJ0aXN0X25hbWUsYWxidW1fcmVsZWFzZV9kYXRlLGRhbmNlYWJpbGl0eSxpbnN0cnVtZW50YWxuZXNzLGVuZXJneSx2YWxlbmNlLCBrZXlfbmFtZSxtb2RlX25hbWUpICU+JSAga2FibGUoZm9ybWF0ID0gInNpbXBsZSIsIGNvbC5uYW1lcyA9IHN0cl90b190aXRsZShnc3ViKCJbX10iLCAiICIsIGNvbG5hbWVzKC4pKSksYWxpZ24gPSAnbGNjY2NjY2NjYycsY2FwdGlvbiA9ICJBbiBleGFtcGxlIHRhYmxlIGNhcHRpb24uIixkaWdpdHMgPSAzKQpgYGAKCiMjIEx5cmljczogR2VuaXVzIEFQSQoKQXMgZm9yIFNwb3RpZnkncyBBUEksIHRoZSBHZW5pdXMgQVBJIHJlcXVpZXJlcyBhIGRldmVsb3BlcnMgYWNjb3VudCBpbiBvcmRlciB0byBxdWVyeSBpbmZvcm1hdGlvbi4gVG8gYXV0aGVudGljYXRlIHRoZSBpbmZvcm1hdGlvbiB0aGUgdXNlciBtdXN0OiAxLiBDcmVhdGUgYSBgR2VuaXVzIEFQSSBjbGllbnRgIFtoZXJlXShodHRwczovL2dlbml1cy5jb20vYXBpLWNsaWVudHMvbmV3KSwgMi4gZ2VuZXJhdGUgYSBgY2xpZW50IGFjY2VzcyB0b2tlbmAgZm9ybSB0aGUgW0FQSSBDbGllbnRzIFBhZ2VdKGh0dHBzOi8vZ2VuaXVzLmNvbS9hcGktY2xpZW50cykgYW5kIDMuIHNldCB5b3VyIGNyZWRlbnRpYWwgaW4gdGhlIFN5c3RlbSBlbnZpcm9ubWVudCB2YXJpYWJsZSBgR0VOSVVTX0FQSV9UT0tFYCBjYWxsaW5nIHRoZSBmdW5jdGlvbiBgZ2VuaXVzX3Rva2VuKClgLiBOb3csIGluIG9yZGVyIHRvIGZlY3RoIHRoZSBseXJpY3MgZm9yIGVhY2ggc29uZyBJIGNyZWF0ZWQgYSBsb29wIHRoYXQgZ29lcyB0cmhvdWdoIGV2ZXJ5IHNvbmcgaW4gdGhlIGRhdGEgc2V0IGFuZCByZXRyaWV2ZXMgdGhlIGx5cmljcyBpbiBhIHNpbmdsZSB2ZWN0b3IgYW5kIHRoZW4gYWRkcyBpdCB0byB0aGUgY3JlYXRlIHZhcmlhYmxlIGBseXJpY3MyYC4KCmBgYHtyLCBldmFsID0gRn0gCnBqIDwtIG11dGF0ZShwaiwgbHlyaWNzMiA9ICIiKQpmb3IgKGVsZW1lbnQgaW4gKDE6bnJvdyhwaikpKSB7CiAgCiAgIyBJIGNyZWF0ZWQgdGhlIGxvb3Agd2l0aCB0d28gY2ljbGVzIGluIGl0IGluIG9yZGVyIHRvIGRvdWJsZSBjaGVjayBhbGwgdGhlIHNvbmdzIAogICMgZ2V0IHRoZWlyIGNvcnJlc3BvbmRpbmcgbHlyaWNzLiBOb3RlIHRoYXQgdGhlIGxvb3AgaXNvbGF0ZXMgZWFjaCBzb25nIGFuZAogICMgcmV0cmlldmVzIHRoZSBpbmZvcm1hdGlvbiB3aXRoIHRoZSBmdW5jdGlvbiBldF9seXJpY3Nfc2VhcmNoKCkKICAKICB0aXRsZSA8LSBzdHJfdG9fdGl0bGUocGokdHJhY2tfbmFtZVtlbGVtZW50XSkgCiAgcHJpbnQodGl0bGUpCiAgbHlyaWNzIDwtIGdldF9seXJpY3Nfc2VhcmNoKGFydGlzdF9uYW1lID0gIlBlYXJsIEphbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNvbmdfdGl0bGUgPSB0aXRsZSkKICBpZiAobnJvdyhseXJpY3MpIT0wKSB7CiAgICAjIEkgb3B0ZWR0byByZWR1Y2UgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIHJldHJpZXZlZCBkYXRhIHNldCB0byAgb25lIG9ic2VydmF0aW9uLgogICAgIyBOb3cgSSBzYXZlIHRoZSBmaXJzdCBsaW5lIGFuZCBhZGQgdGhlIHJlc3Qgb2YgdGhlIGxpbmVzIG9mIHRoZSBzb25nCiAgbHlyaWNzMiA8LSAiIgogICAgZm9yIChwaWVjZSBpbiAoMTpucm93KGx5cmljcykpKSB7CiAgICBpZiAocGllY2UgPT0xKSB7CiAgICAgIGx5cmljczIgPC0gbHlyaWNzJGxpbmVbcGllY2VdCiAgICB9CiAgICBlbHNlewogICAgICBseXJpY3MyIDwtIHBhc3RlKGx5cmljczIsIGx5cmljcyRsaW5lW3BpZWNlXSwgY29sbGFwc2UgPSAiICIpCiAgICB9CiAgICBwcmludCh0aXRsZSkKICAgIHByaW50KGx5cmljczIpCiAgICB9CiAgfQogIAogICMgSWYgYW55IHNvbmcgaGFkIGFueSBwcm9ibGVtIHdpdGggcXVlcnlpbmcgdGhlIGx5cmljcyB0aGUgc2Vjb25kIHBhcnQgb2YgdGhlIGxvb3AKICAjIHJlcGVhdHMgdGhlIHByb2NjZXMgdG8gZ3VhcmFudGVlIHRoYXQgYWxsIHNvbmdzIGFyZSBhc3NpbmdlZCB0byB0aGVpciBseXJpY3MuCiAgCiAgaWYgKG5yb3cobHlyaWNzKT09MCkgewogICAgbHlyaWNzIDwtIGdldF9seXJpY3Nfc2VhcmNoKGFydGlzdF9uYW1lID0gIlBlYXJsIEphbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc29uZ190aXRsZSA9IHRpdGxlKQogICAgbHlyaWNzMiA8LSAiIgogICAgZm9yIChwaWVjZSBpbiAoMTpucm93KGx5cmljcykpKSB7CiAgICAgIGlmIChwaWVjZSA9PTEpIHsKICAgICAgICBseXJpY3MyIDwtIGx5cmljcyRsaW5lW3BpZWNlXQogICAgICB9CiAgICAgIGVsc2V7CiAgICAgICAgbHlyaWNzMiA8LSBwYXN0ZShseXJpY3MyLCBseXJpY3MkbGluZVtwaWVjZV0sIGNvbGxhcHNlID0gIiAiKQogICAgICB9CiAgICAgIHByaW50KHRpdGxlKQogICAgICBwcmludChseXJpY3MyKQogICAgfQogIH0KICAKICAjIEZpbmFsbHkgdGhlIHNvbmcgaXMgYWRkZWQgdG8gdGhlIG9yaWdpbmFsIGRhdGEKICAKICBwaiRseXJpY3MyW2VsZW1lbnRdIDwtIGx5cmljczIKfQpgYGAKCk91ciBkYXRhIHNldCBub3cgY29udGFpbnMgbHlyaWNzIHRvIGFsbCB0aGUgMTQ2IHNvbmdzIGluIHRoZSAxMSBhbGJ1bXMuIEEgZ2xpbXBzZSB0byBteSB0b3AgdHdvIFBlYXJsIEphbSBzb25ncyAoYWNjb3JkaW5nIHRvIHNwb3RpZnkgcmFua2luZ3MpIEJsYWNrIGFuZCBFdmVuIGZsb3c6CgpgYGAge3IsIGV2YWw9VCAsaW5jbHVkZT1GfSAKcGokdHJhY2tfbmFtZSA8LSBzdHJfdG9fdGl0bGUocGokdHJhY2tfbmFtZSkKYGBgCgpgYGAge3J9CnNvbmdzIDwtIGMoJ0JsYWNrJywgJ0V2ZW4gRmxvdycpCnBqW3BqJHRyYWNrX25hbWUgJWluJSBzb25ncyxdICU+JSBzZWxlY3QoYXJ0aXN0X25hbWUsIGFsYnVtX25hbWUsIHRyYWNrX25hbWUsIGx5cmljcykgJT4lIAogIGthYmxlKGZvcm1hdCA9ICJzaW1wbGUiLGNvbC5uYW1lcyA9IHN0cl90b190aXRsZShnc3ViKCJbX10iLCAiICIsIGNvbG5hbWVzKC4pKSksYWxpZ24gPSAnbGNjY2NjY2NjYycpCmBgYAoKRmluYWxseSwgd2UgaGF2ZSB0byB0YWtlIGludG8gYWNjb3VudCBpbnN0dW1lbnRhbCBzb25ncy4gRXZlbiB0aG91Z2ggUGVhcmwgSmFtIGRvZXNuJ3QgaGF2ZSBtYW55IGluc3RydW1lbnRhbCBzb25ncyAzIGNhc2VzIG5lZWQgdG8gYmUgYWRyZXNzZWQuIHRoZXNlIGFyZSAqKkFyYyoqLCAqKkF5YSBEYXZhbml0YSoqIGFuZCAqKkNyZWFkeSBTdG9tcCoqLiBJIHByb2NlZCB0aGVuIHRvIGFzc2luZyBhIG1pc3NpbmcgdmFsdWUgdG8gdGhlc2Ugc29uZ3MgaW4gb3JkZXIgdG8gaW1wbGVtZW50IHRoZSBmb2xsb3dvbmcgYW5hbHlzaXMuCmBgYCB7ciwgZXZhbCA9IFR9CnNvbmdzIDwtIGMoIkFyYyIsIkF5YSBEYXZhbml0YSAtIFJlbWFzdGVyZWQiLCJDcmVhZHkgU3RvbXAgLSBCb251cyBUcmFjayIpCnBqW3BqJHRyYWNrX25hbWUgJWluJSBzb25ncyxncmVwKCdseXJpY3MnLCBjb2xuYW1lcyhwaikpXQpwaltwaiR0cmFja19uYW1lICVpbiUgc29uZ3MsZ3JlcCgnbHlyaWNzJywgY29sbmFtZXMocGopKV0gPC0gTkEKYGBgCgojIERhdGEgZXhwbG9yYXRpb24KIyMgVG9rZW5zICYgZGF0YSB3cmFuZ2xpbmcKClRoZSBkYXRhc2V0IGlzIGFsbW9zdCByZWFkeSBmb3IgdXNlLiBJIG5vdyBleGVjdXRlIHNvbWUgZmV3IGRhdGEgd3JhbmdsaW5nIHN0ZXBzIGluIG9yZGVyIHRvIGhhdmUgYWxsIHRoZSBpbmZvcm1hdGlvbiBuZWVkZWQuIEkgdXNlIHRoZSBwYWNrYWdlIGB0bWAgaW4gb3JkZXIgdG8gcmVtb3ZlIHB1bmN0dWF0aW9uLCBzdG9wIHdvcmRzIGFuZCBzdGVtbWluZy4gSSBiZWdpbiBieSBjb21waWxpbmcgYWxsIGx5cmljcyBhbmQgY3JlYXRlIGEgY29ycHVzIHVzaW5nIHRoZSBmdW5jdGlvbiBgVmVjdG9yU291cmNlYCB0byByZWFkIGl0IGEgcyBhIGRvY3VtZW50IGFuZCB0aGVuIHBhc3MgdGhlIGRvY3VtZW50cyB0aHJvdWdoIHRoZSBgQ29ycHVzYCB0byBjcmVhdGUgdGhlIGZpbmFsIGNvcnB1cy4gTm90ZSB0aGF0IGFsbCB0aGUgZG9jdW1lbnQgdHJhbnNmb3JtYXRpb24gb2YgdGhlIGRvY3VtZW50IGFyZSBkb25lIHRocm91Z2ggdGhlIGZ1bmNpdG9uIGB0bV9tYXBgLCBhcHBseWluZyBhIGZ1bmN0aW9uIHRvIGFsbCBlbGVtZW50cyBvZiB0aGUgZG9jdW1lbnQuIFRoZSBwcm9jZXNzIEkgZm9sbG93IGlzOiAqKjEpKiogdHJhbnNmb3JtIGFsbCB1cHBlci1jYXNlIGxldHRlciB0byBsb3dlci1jYXNlOyAqKjIpKiogcmVtb3ZlIGFsbCBwdW5jdGlvbmF0aW9uOyAqKjMpKiogcmVtb3ZlIEVuZ2xpc2ggc3RvcCB3b3JkczsgYW5kICoqNCkqKiBzdGVtIGFsbCB0aGUgd2hpdGUgc3BhY2VzLgoKYGBgIHtyLCBldmFsPVQsaW5jbHVkZSA9IEZ9Cmx5cmljcyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHBqJGx5cmljcykpCmx5cmljcyA8LSB0bV9tYXAobHlyaWNzLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQpseXJpY3MgPC0gdG1fbWFwKGx5cmljcywgcmVtb3ZlUHVuY3R1YXRpb24pCmx5cmljcyA8LSB0bV9tYXAobHlyaWNzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCJlbmdsaXNoIikpCmx5cmljcyA8LSB0bV9tYXAobHlyaWNzLCBzdHJpcFdoaXRlc3BhY2UpCmx5cmljcyA8LSBseXJpY3MgJT4lIHVubGlzdCgpCnBqJGx5cmljcyA8LSBhcy5jaGFyYWN0ZXIobHlyaWNzWzE6bnJvdyhwaildKQpwaiRseXJpY3MgPC0gc3RyX3RyaW0ocGokbHlyaWNzKQoKYGBgCgpgYGAge3IsIGV2YWw9RixpbmNsdWRlID0gVH0KbHlyaWNzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UocGokbHlyaWNzKSkKbHlyaWNzIDwtIHRtX21hcChseXJpY3MsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCmx5cmljcyA8LSB0bV9tYXAobHlyaWNzLCByZW1vdmVQdW5jdHVhdGlvbikKbHlyaWNzIDwtIHRtX21hcChseXJpY3MsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoImVuZ2xpc2giKSkKbHlyaWNzIDwtIHRtX21hcChseXJpY3MsIHN0cmlwV2hpdGVzcGFjZSkKbHlyaWNzIDwtIGx5cmljcyAlPiUgdW5saXN0KCkKcGokbHlyaWNzIDwtIGFzLmNoYXJhY3RlcihseXJpY3NbMTpucm93KHBqKV0pCnBqJGx5cmljcyA8LSBzdHJfdHJpbShwaiRseXJpY3MpCgpgYGAKCkFmdGVyIHByb2Nlc2luZyB0aGUgbHlyaWNzIHRoZXJlJ3Mgc3RpbGwgc29tZSBzcGVjaWFsIGNhc2VzIHRoYXQgbmVlZCB0byBiZSB0YWtlbiBpbnRvIGFjY291bnQgaXIgb3JkZXIgdG8gcHJldmVudCBiaWFzIGluIHRoZSByZXN1bHRzLiBGaXJzdCwgd29yZCBjb250cmFjdGlvbnMgbmVlZCB0byBiZSBhZGRyZXNzZWQuIEFzIEkgcmVtb3ZlZCBhbGwgcHVuY3R1YXRpb24gYmVmb3JlLCBzb21lIGNvbnRyYWN0aW9ucyBzdWNoIGFzICoqc2hlJ3MqKiB3aWxsIGJlIG5vdyAqKnNoZXMqKiBhbmQgYXJlIG5vdCB0YWtlbiBhcyBzdG9wIHdvcmRzIGJ5IHRoZSBmdW5jdGlvbiBgdG1fbWFwYC4gT3RoZXIgY2FzZXMgYXJlIHJ5dGhtaXRpYyB2b2NhbHMuIFRha2UgQmxhY2sgYXMgYW4gZXhhbXBsZS4gVGhlIGxhc3QgbWludXRlIG9mIHRoZSBzb25nIEVkZGllIGdvZXMgb24gbGlrZSAqKmRvbyBkb28gZG9vIGRvbyBkb28gZG9vIGRvbyoqLiBJbiBvcmRlciB0byBwcmV2ZW50IGJpYXNlZCByZXN1bHRzIEkgb21taXQgYWxsIHJ5dGhtaXRpYyB2b2NhbHMgYW5kIHJlcGxhY2UgdGhlIGNvbnRyYWN0aW9ucyBieSB0aGVpciByZXNwZWN0aXZlIGpvaW50IHdvcmRzLgoKYGBgIHtyLCBldmFsID0gVH0KCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnYm90dG9tb2gnLCAnIGJvdHRvbSBvaCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBoZXlpbSAnLCAnIGhleSBJIGFtICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGRlZXBvaCAnLCAnIGRlZXAgb2ggJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgYnV0dGVyZmxpZXNkb250ICcsICcgYnV0dGVyZmxpZXMgZG8gbm90ICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGF3YXlzb21lZGF5ICcsICcgYXdheSBzb21lZGF5ICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHJpc2luZ25leHQgJywgJyByaXNpbmcgbmV4dCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB1aG9ob2ggJywgJyBvaCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBhbmdlbGxlc3QgJywgJyBhbmdlbCBsZXRzICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGRvb2Rvb2Rvb2Rvb2Rvb2Rvb2RvbyAnLCAnJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgeWVhaCAnLCAnICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHllYWgnLCAnICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIG9vaCAnLCAnICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIG9oICcsICcgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgYWggJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBobSAnLCAnICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHllICcsICcgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgYXkgJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB5ZWggJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB5YSAnLCAneW91JykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgbW0gJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBpbnRlcmx1ZGUgJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB3b28gJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBtaG0gJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBvb29oICcsICcgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgb29vb2ggJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBoZXkgJywgJyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB1aCAnLCAnICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHlvdWxsICcsICcgeW91IHdpbGwgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgY2FudCAnLCAnIGNhbiBub3QgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICdjYW50ICcsICcgY2FuIG5vdCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBpbSAnLCAnIEkgYW0gJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgaWxsICcsICcgSSB3aWxsICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGRpZG50ICcsICcgZGlkIG5vdCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBkb250ICcsICcgZG8gbm90ICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGhlcyAnLCAnIGhlIGlzICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHVoaHVoICcsICcnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyBpdHMnICwgJycpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGlkICcsICcgSSB3b3VsZCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB5b3VyZSAnLCAnIHlvdSBhcmUgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgeW91dmUgJywgJyB5b3UgaGF2ZSAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB5b3VkICcsICcgeW91IHdvdWxkICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHRoZXJlcyAnLCAnIHRoZXJlIGlzICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHRoZXlsbCAnLCAnIHRoZXkgd2lsbCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB3aGF0cyAnLCAnIHdoYXQgaXMgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgZG9lc250ICcsICcgZG9lcyBub3QgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgaXZlICcsICcgSSBoYXZlICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIGhhZG50ICcsICcgaGFkIG5vdCAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB3b3VsZG50ICcsICcgd291bGQgbm90ICcpCnBqJGx5cmljcyA8LSBzdHJfcmVwbGFjZV9hbGwocGokbHlyaWNzLCAnIHRpbCAnLCcgdW50aWwgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgd291bGR2ZSAnLCAnIHdvdWxkIGhhdmUgJykKcGokbHlyaWNzIDwtIHN0cl9yZXBsYWNlX2FsbChwaiRseXJpY3MsICcgc2hlcyAnLCAnIHNoZSBpcyAnKQpwaiRseXJpY3MgPC0gc3RyX3JlcGxhY2VfYWxsKHBqJGx5cmljcywgJyB0aGF0cyAnLCAnIHRoYXQgaXMgJykKYGBgCgpPbmUgbGFzdCBzdGVwIGludG8gb3VyIGZpbmFsIGRhdGFzZXQgaXMgd29yZCBzZW50aW1lbnQuIEkgdGhlbiB0dXJuIHRoZSBkYXRhIGludG8gYSB0aWR5IGZvcm1hdCB1c2luZyB0aGUgcGFja2FnZSBgdGlkeXRleHRgLiBJIHVzZSB0aGUgZnVuY3Rpb24gYHVubmVzdF90b2tlbnNgIGluIG9yZGVyIHRvIHNwbGl0IHRoZSBseXJpY3MgaW50byBpbmRpdnVkdWFsIHdvcmRzLiB0aGUgZnVuY3Rpb24gYGdldF9zZW50aW1lbnRzYCBpcyB1c2VkdG8gb2J0YWluIHRoZSBzZW50aW1lbnRzIGxleGljb24gaW4gYSB0aWR5IGZvcm1hdC4gVGhlIGxleGljb24gdXNlZCBpcyBgTkNSYCAqKldvcmQtRW1vdGlvbiBBc3NvY2lhdGlvbiBMZXhpY29uKiouIFRoaXMgbGV4aWNvbiBsaXN0cyBFbmdsaXNoIHdvcmRzIGFuZCBtYXRjaGVzIHRoZWlyIGFzc29jaWF0aW9ucyB3aXRoIGVpZ2h0IGJhc2ljIGVtb3Rpb25zIChhbmdlciwgZmVhciwgYW50aWNpcGF0aW9uLCB0cnVzdCwgc3VycHJpc2UsIHNhZG5lc3MsIGpveSwgYW5kIGRpc2d1c3QpIGFuZCB0d28gc2VudGltZW50cyAobmVnYXRpdmUgYW5kIHBvc2l0aXZlKS4gRnVydGhlciBpbmZvcm1hdGlvbiBjb3VsZCBiZSBmb3VuZCBpbiB0aGUgb2ZmaWNpYWwgW3dlYiBwYWdlXShodHRwczovL3NhaWZtb2hhbW1hZC5jb20vV2ViUGFnZXMvTlJDLUVtb3Rpb24tTGV4aWNvbi5odG0pLiBXaXRoIHRoZSAgc2VudGltZW50cyBtYXRjaGVkIEknbSBhYmxlIHRvIGNvdW50IHRoZSBudW1iZXIgb2Ygd29yZHMgcGVyIGVtb3Rpb24gYW5kIHNlbnRpbWVudC4KYGBgIHtyLCBldmFsID1GLCBpbmNsdWRlID0gVH0KCnBlYXJsX3NvbmdzIDwtIHBqICU+JSB1bm5lc3RfdG9rZW5zKHdvcmQsIGx5cmljcykgIyBTZXBhcmF0ZSB0aGUgbHlyaWNzIGludG8gc2luZ2xlIHdvcmRzCmNsZWFuZWRfcGVhcmwgPC0gcGVhcmxfc29uZ3MgJT4lIGFudGlfam9pbihzdG9wX3dvcmRzKSAjIEVsaW1pbmF0aW5nIHN0b3Agd29yZHMKbnJjIDwtIGdldF9zZW50aW1lbnRzKGxleGljb24gPSAibnJjIikgIyBDYXRlZ29yaWNhbCB3b3JkcyBzZW50aW1lbnRzCgpwZWFybF9zZW50aW1lbnQgPC0gY2xlYW5lZF9wZWFybCAlPiUKICBpbm5lcl9qb2luKG5yYyxieSA9IGMoJ3dvcmQnKSkgJT4lICMgTWVyZ2luZyB0aGUgd29yZCBzZW50aW1lbnQgZGF0YSB3aXRoIHRoZSB3b3JkcyBkYXRhc2V0CiAgY291bnQodHJhY2tfbmFtZSwgc2VudGltZW50KSAlPiUgIyBDb3VudGluZyB0aGUgbnVtYmVyIG9mIHdvcmRzIHBlciBzZW50aW1lbnQKICBzcHJlYWQoc2VudGltZW50LCBuLCBmaWxsID0gMCkgIyBSZXNoYXBpbmcgdGhlIGRhdGEgZnJvbSBvYnNlcnZhdGlvbnMgaW50byBjb2x1bW5zCgpjb2x1bW5zIDwtIGMoZ3JlcCgnYWxidW1fbmFtZScsIGNvbG5hbWVzKHBqKSksCiAgICAgICAgICAgICBncmVwKCd0cmFja19uYW1lJywgY29sbmFtZXMocGopKSkKCnBlYXJsX3NlbnRpbWVudCA8LSBpbm5lcl9qb2luKHggPSBwZWFybF9zZW50aW1lbnQsIHkgPSBwalssY29sdW1uc10sIGJ5ID0gInRyYWNrX25hbWUiKQpwaiA8LSBpbm5lcl9qb2luKHBqLCBwZWFybF9zZW50aW1lbnQpCgpgYGAKCmBgYCB7ciwgZXZhbCA9VCxpbmNsdWRlID0gRn0KCnBlYXJsX3NvbmdzIDwtIHBqICU+JSB1bm5lc3RfdG9rZW5zKHdvcmQsIGx5cmljcykKY2xlYW5lZF9wZWFybCA8LSBwZWFybF9zb25ncyAlPiUgYW50aV9qb2luKHN0b3Bfd29yZHMpCm5yYyA8LSBnZXRfc2VudGltZW50cyhsZXhpY29uID0gIm5yYyIpCiMgCnBlYXJsX3NlbnRpbWVudCA8LSBjbGVhbmVkX3BlYXJsICU+JQogIGlubmVyX2pvaW4obnJjLGJ5ID0gYygnd29yZCcpKSAlPiUKICBjb3VudCh0cmFja19uYW1lLCBzZW50aW1lbnQpICU+JQogIHNwcmVhZChzZW50aW1lbnQsIG4sIGZpbGwgPSAwKQoKY29sdW1ucyA8LSBjKGdyZXAoJ2FsYnVtX25hbWUnLCBjb2xuYW1lcyhwaikpLAogICAgICAgICAgICAgZ3JlcCgndHJhY2tfbmFtZScsIGNvbG5hbWVzKHBqKSkpCgpwZWFybF9zZW50aW1lbnQgPC0gaW5uZXJfam9pbih4ID0gcGVhcmxfc2VudGltZW50LCB5ID0gcGpbLGNvbHVtbnNdLCBieSA9ICJ0cmFja19uYW1lIikKcGogPC0gaW5uZXJfam9pbihwaiwgcGVhcmxfc2VudGltZW50KQoKYGBgCgojIyBHbG9vbSBJbmRleAoKV2l0aCB0aGUgZmluYWwgZGF0YXNldCBJJ20gYWJsZSB0byBkbyBzb21lIHNvcnQgb2YgYW5hbHlzaXMgdG8gUGVhcmwgSmFtJ3MgZGlzY29ncmFwaHkuIEF0IGZpcnN0IGhhbmQgSSB3YXMgaW50ZXJlc3RlZCBpbiBmaW5kaW5nIHNvbWUgbWV0cmljIG9mIHNhZG5lc3MgaW4gYSBtdXNpY2FsIGNvbnRleHQuIE9uZSBvZiB0aGUgbW9zdCBpbnRlcmVzdGluZyBhbmFseXNpcyB0YWtpbmcgdGhpcyBpbnRvIGFjY291bnQgaXMgdGhlIFtHbG9vbSBJbmRleF0oaHR0cHM6Ly93d3cucmNoYXJsaWUuY29tL2Jsb2cvZml0dGVyLWhhcHBpZXIvKSBkZXZlbG9wZWQgYnkgW0NoYXJsaWUgVGhvbXBzb25dKGh0dHBzOi8vd3d3LnJjaGFybGllLmNvbSkuIEhlcmUgdGhlIGF1dGhvciB1c2VzIHRoZSBpbmZvcm1hdGlvbiBvbiB0aGUgdmFsZW5jZSBvZiB0aGUgc29uZywgdGhlIHBlcmNlbnRhZ2Ugb2Ygc2FkIHNvbmdzIGFuZCB0aGUgbHlyaWNhbCBkZW5zaXR5IG9mIHRoZSBzb25nLiBJbiB0ZXJtcyBvZiB2YWxlbmNlLCBTcG90aWZ5IHVzZXMgYSB3aWRlIHZhcmlldHkgb2YgaW5wdXRzIHRvIGRldGVybWluZSB3ZWF0aGVyIGEgc29uZ3Mgc291bmQgaGFwcHkgb3Igbm90LiBXaXRoIHRoaXMgaW4gbWluZCBzYWQgc29uZ3MgaGF2ZSBhIGxvd2VyIHZhbGVuY2Ugc2NvcmUgYW5kIGhhcHB5IHNvbmdzIGhhdmUgaGlnaCB2YWxlbmNlLiBIZXJlJ3MgYSBwcmV2aWV3IG9mIHNvbWUgb2YgUGVhcmwgSmFtJ3Mgc2FkZGVzdCBzb25ncyBhY2NvcmRpbmcgdGhpcyBtZWFzdXJlOgoKYGBge3J9CnBqICU+JSBncm91cF9ieSh0cmFja19uYW1lKSAlPiUgc3VtbWFyaXNlKHZhbGVuY2UgPSBtZWFuKHZhbGVuY2UpKSAlPiUgYXJyYW5nZSh2YWxlbmNlKSAlPiUgaGVhZCgxMCkgJT4lIGthYmxlKGZvcm1hdCA9ICJzaW1wbGUiLCBjb2wubmFtZXMgPSBzdHJfdG9fdGl0bGUoZ3N1YigiW19dIiwgIiAiLCBjb2xuYW1lcyguKSkpLGFsaWduID0gJ2xjJyxjYXB0aW9uID0gIlRvcCB0ZW4gc2FkZGVzdCBQZWFybCBKYW0gc29uZ3MgLSBWYWxlbmNlIHNjb3JlIixkaWdpdHMgPSAzKQpgYGAKCk9yaWdpbmFsbHkgdGhlIGluZGV4IHRha2VzIHRoZSBmb2xsb3dpbmcgZm9ybToKCiQkR2xvb21cO0luZGV4ID0gXGZyYWN7KDEtdmFsZW5jZSkgKyBwZXJjZW50YWdlXF9zYWQoMStseXJpY2FsXF9kZW5zaXR5KX17Mn0kJApOb3csIG5vdGluZyB0aGF0IHRoZSBseXJpY2FsIGRlbnNpdHkgbWlndGggYmUgbWlzbGVhZGluZyBJIHR1cm4gdG8gb3RoZXIgbWVhc3VyZSBvZiBseXJpY2FsIGRlbnNpdHkuIExvbmdlciBzb25ncyBtaWdodCBoYXZlIG1vcmUgcmVwZWF0ZWQgbHlyaWNzIHRoYW4gc2hvcnRlciBzb25ncy4gVGhpcyBjYW4gYmUgZWl0aGVyIGJ5IG1vcmUgY2hvcnVzZXMgb3IgYnJpZGdlcywgYnV0IHRoZSByZXN1bHRzIG1pZ2h0IGJlIHdyb25nIGZvciB0aGlzIHJlYXNvbi4gQWNjb3VudGluZyBmb3IgdGhpcyBwcm9ibGVtIGEgY2xlYW5lciBtZXRyaWMgZm9yIGx5cmljYWwgZGVuc2l0eSBpcyB0aGUgcmF0aW8gb2YgZGlzdGljbnQgd29yZHMgYW5kIHRvdGFsIHdvcmRzIHVzZWQuCiQkR2xvbW1cOyBJbmRleCA9IFxmcmFjeygxLXZhbGVuY2UpK3BlcmNlbnRhZ2VcX3NhZCgxK2Rpc3RpbmN0XF9wZXJjZW50YWdlKX17Mn0kJCAKCldoZXJlCgokJGRpc3RpbmN0XF9wZXJjZW50YWdlID0gXGZyYWN7XCMgZGlzdGluY3QgXDt3b3Jkc317XCMgdG90YWwgd29yZHN9JCQKCk5vdywgaGF2aW5nIHRoaXMgaW5mb3JtYXRpb24gaG93IGNhbiB0aGlzIGluZGV4IGJlIGludGVycHJldGVkPyBXZSBuZWVkIHRvIHVuZGVyc3RhbmQgaG93IGdsb29tIG1vdmVzIGFsb25nIHRoZSBkaWZmZXJlbnQgaW5wdXRzLiBGaXJzdCwgdmFsZW5jZSBzaG93cyBoaWdoZXIgdmFsdWVzIGZvciBoYXBweSBzb25ncyB3aGlsc3QgbG93IHZhbHVlcyBmb3Igc2FkIHNvbmdzLiBOb3csIGJ5IHN1YnRyYWN0aW5nIHRoZSB2YWxlbmNlLCBhIHNvbmcgd2l0aCBsb3dlciB2YWxlbmNlIHdpbGwgaGF2ZSBhIGhpZ2hlciBpbmRleCBzY29yZS4gSW4gb3RoZXIgd29yZHMsIHZhbGVuY2UgaGFzIGFuIGludmVyc2UgcmVsYXRpb25zaGlwIHdpdGggdGhlIGdsb29tIGluZGV4LiBOb3csIHR1cmJ1bGVudCB3b3JkcyBhbmQgZGlzdGluY3Qgd29yZHMgcGVyY2VudGFnZSBsb2dpY2FsbHkgbW92ZSBpbiB0aGUgc2FtZSBkaXJlY3Rpb24gb2YgdGhlIGdsb29tIGluZGV4LiBJIGNhbiBub3cgc2F5IHRoYXQgKioqaGlnaGVyIHZhbHVlcyBzaG93IHNhZGRlciBzb25ncywgd2hpbGUgbG93ZXIgdmFsdWVzIHJlcHJlc2VudCBoYXBwaWVyIHNvbmdzKioqLiBOb3RlIHRoYXQgY29tcGFyZWQgdG8gQ2hhcmxpZSdzIFtSYWRpb2hlYWQgYW5hbHlzaXNdKGh0dHBzOi8vd3d3LnJjaGFybGllLmNvbS9ibG9nL2ZpdHRlci1oYXBwaWVyLykgbXkgaW5kZXggaXMgaW50ZXJwcmV0ZWQgaW4gYSBjb21wbGV0ZWx5IGRpZmZlcmVudCB3YXkuIFRoZSBtYWluIHJlYXNvbiBpcyBiZWNhdXNlIENoYXJsaWUgcmVzY2FsZXMgaGlzIGluZGV4IGluIG9yZGVyIHRvIHJlcHJlc2VudCBoYXBweSBzb25ncyB3aXRoIGhpZ2hlciB2YWx1ZXMuIE5vdywgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSByZXN1bHRzIGFyZSBhbmFsb2dvdXMsIHRoZSBvbmx5IGRpZmZlcmVuY2UgYXJlIHRoZSBzY2FsZSBpbiB3aGljaCB0aGV5IGFyZSBwcmVzZW50ZWQuCgpgYGB7ciwgZXZhbCA9IFR9CnBqIDwtIHBqICU+JSB1bm5lc3RfdG9rZW5zKHdvcmQsIGx5cmljcykgJT4lCiAgZ3JvdXBfYnkodHJhY2tfbmFtZSkgJT4lIHN1bW1hcmlzZShkaXN0aW5jdF93b3JkcyA9IG5fZGlzdGluY3Qod29yZCkpICU+JSAKICBpbm5lcl9qb2luKHBqKQoKcGogPC0gbXV0YXRlKHBqLCB3b3JkcyA9IHNhcHBseShzdHJzcGxpdChwaiRseXJpY3MsICIgIiksIGxlbmd0aCkpCnBqIDwtIG11dGF0ZShwaiwgc2Vjb25kcyA9IGR1cmF0aW9uX21zLzEwMDApCnBqIDwtIG11dGF0ZShwaiwgd29yZHNfcGVyX3NlY29uZCA9IHdvcmRzL3NlY29uZHMpCnBqIDwtIG11dGF0ZShwaiwgc2FkX3BlcmNlbnRhZ2UgPSBzYWRuZXNzL2Rpc3RpbmN0X3dvcmRzKQpwaiA8LSBtdXRhdGUocGosIGRpc3RfcGVyID0gKGRpc3RpbmN0X3dvcmRzL3dvcmRzKSkKcGogPC0gbXV0YXRlKHBqLCBpbmRleCA9ICgoMS12YWxlbmNlKStzYWRfcGVyY2VudGFnZSooMStkaXN0X3BlcikpLzIpCmBgYAoKCkkgY2FuIG5vdyB2aXp1YWxpemUgZGlmZmVyZW50IGluZm9ybWF0aW9uIEkgaGF2ZSBnYXRoZXJlZCBhbG9uZyB0aGUgZG9jdW1lbnQuIEZpcnN0LCB3ZSBjYW4gc2VlIHRoZSBzYWRkZXN0IHNvbmdzIGFjY29yZGluZyB0byB0aGUgR2xvb20gSW5kZXguIAoKCmBgYHtyLCBldmFsID0gVH0KcGogJT4lIGdyb3VwX2J5KHRyYWNrX25hbWUsYWxidW1fbmFtZSkgJT4lIAogIHN1bW1hcmlzZShpbmRleCA9IG1lYW4oaW5kZXgpLAogICAgICAgICAgICB2YWxlbmNlID0gbWVhbih2YWxlbmNlKSwKICAgICAgICAgICAgYHR1cmJ1bGVudCB3b3Jkc2AgPSBtZWFuKHNhZF9wZXJjZW50YWdlKSwKICAgICAgICAgICAgYGRpc3RpbmN0IHBlcmNlbnRhZ2Ugd29yZHNgID0gbWVhbihkaXN0X3BlcikpICU+JSBhcnJhbmdlKGRlc2MoaW5kZXgpKSAlPiUgaGVhZCgxMCkgJT4lIGthYmxlKGZvcm1hdCA9ICJzaW1wbGUiLCBjb2wubmFtZXMgPSBzdHJfdG9fdGl0bGUoZ3N1YigiW19dIiwgIiAiLCBjb2xuYW1lcyguKSkpLGFsaWduID0gJ2xjY2NjYycsY2FwdGlvbiA9ICJUb3AgdGVuIHNhZGRlc3QgUGVhcmwgSmFtIHNvbmdzIC0gR2xvb20gSW5kZXgiLGRpZ2l0cyA9IDMpCmBgYAoKV2UgaGF2ZSBub3cgdGhlIG1vc3QgZGVwcmVzc2luZyBQZWFybCBKYW0gc29uZyB0byBkYXRlOiAqKlNwaW4gdGhlIEJsYWNrIENpcmNsZSoqLiBCdXQgaG93IGNhbiBpdCBiZT8gQW55b25lIHdobyBoYXZlIGhlYXJkIHRoZSByaWd0aCBhbW1vdW50IG9mIHRoZWlyIHNvbmdzIGNvdWxkIGFyZ3VlIGluIGZhdm9yIG9mIFJlbGVhc2Ugb3IgQWxsIHRob3NlIHllc3RlcmRheXMsIG9yIGV2ZW4gQmxhY2ssIGJ1dCByZW1lbWJlciB0aGF0IHRoaXMgaXMgYSBkYXRhIGRyaXZlbiBtZWFzdXJlLiBTcGluIHRoZSBCbGFjayBDaXJjbGUgYWN0dWFsbHkgaGFzIGEgcmF0aGVyIGxvdyB2YWxlbmNlIHNjb3JlIChtZWFuaW5nIGlzIGEgc2FkIHNvbmcpLCByYW5raW5nIDE5dGggd2l0aCAwLjE0MS4gQnV0IHRoZSBwZXJjZW50YWdlIG9mIHNhZCB3b3JkcyBpcyB0aGUgc2Vjb25kIGhpZ2hlc3Qgb2YgYWxsIHNvbmdzLCBiZWhpbmQgUmVkIEJhciAod2hpY2ggcmVwZWF0cyBzZXZlbiB0aW1lcykgd2loIGEgcGVyY2VudGFnZSBvZiBzYWQgd29yZCBvZiA1MiUuIElmIHRoZSByYW5raW5nIHNlZW1zIG9kZCBsaXN0ZW4gdG8gdGhlIHNvbmdzIGFuZCBzZWUgaXQgZm9yIHlvdXJzZWxmLgoKVG8gc2VlIGhvdyBzYWRuZXNzIG9yIGdsb29tIGhhcyBldm9sdmVkIGFjcm9zcyB0aW1lLCBpcyBwb3NpYmxlIHRvIGF2ZXJhZ2UgdGhlIGluZGV4IHBlciBhbGJ1bSBhbmQgc2VlIHRoZSBkeW5hbWljLiBUaGlzIGlzIHRoZSByYW5raW5nIGZvciB0aGUgc2FkZGVzdCBhbGJ1bXM6CgpgYGB7ciwgZXZhbCA9IFR9CnBqICU+JSBncm91cF9ieShhbGJ1bV9uYW1lKSAlPiUgCiAgc3VtbWFyaXNlKGluZGV4ID0gbWVhbihpbmRleCksCiAgICAgICAgICAgIHZhbGVuY2UgPSBtZWFuKHZhbGVuY2UpLAogICAgICAgICAgICBgc2FkIHdvcmRzYCA9IG1lYW4oc2FkX3BlcmNlbnRhZ2UpLAogICAgICAgICAgICBgZGlzdGluY3QgcGVyY2VudGFnZSB3b3Jkc2AgPSBtZWFuKGRpc3RfcGVyKSkgJT4lIGFycmFuZ2UoZGVzYyhpbmRleCkpICU+JSBoZWFkKDEyKSAlPiUga2FibGUoZm9ybWF0ID0gInNpbXBsZSIsIGNvbC5uYW1lcyA9IHN0cl90b190aXRsZShnc3ViKCJbX10iLCAiICIsIGNvbG5hbWVzKC4pKSksYWxpZ24gPSAnbGNjY2NjJyxjYXB0aW9uID0gIlNhZGRlc3QgUGVhcmwgSmFtIGFsYnVtcyAtIEdsb29tIEluZGV4IixkaWdpdHMgPSAzKQpgYGAKCgoKYGBge3IsIGluY2x1ZGUgPUYsIGV2YWwgPVR9CnJhbmsgPC0gIHBqICU+JSBncm91cF9ieShhbGJ1bV9uYW1lLHRyYWNrX25hbWUsYWxidW1fcmVsZWFzZV95ZWFyKSAlPiUgc3VtbWFyaXNlKGF2ZXJhZ2UgPSBtZWFuKGluZGV4KSkgJT4lIGFycmFuZ2UoYWxidW1fcmVsZWFzZV95ZWFyKQpyYW5rIDwtICBpbm5lcl9qb2luKHJhbmssIHJhbmsgJT4lIGdyb3VwX2J5KGFsYnVtX25hbWUpICU+JSBzdW1tYXJpc2UoZ2xvb21faW5kZXggPSBtZWFuKGF2ZXJhZ2UpKSkKcmFuayA8LSBhcy5kYXRhLmZyYW1lKHJhbmspCgphbGJ1bV9sZXZlbHMgPC0gYygKICAiVGVuIiwgIlZzLiIsICJWaXRhbG9neSIsICJObyBDb2RlIiwgIllpZWxkIiwgIkJpbmF1cmFsIiwgCiAgIlJpb3QgQWN0IiwgIlBlYXJsIEphbSIsICJCYWNrc3BhY2VyIiwgIkxpZ2h0bmluZyBCb2x0IiwgIkdpZ2F0b24iKQoKcmFuayRhbGJ1bV9uYW1lIDwtIGZhY3RvcihyYW5rJGFsYnVtX25hbWUsIGxldmVscyA9IGFsYnVtX2xldmVscykKcGokYWxidW1fbmFtZSA8LSBmYWN0b3IocGokYWxidW1fbmFtZSwgbGV2ZWxzID0gYWxidW1fbGV2ZWxzKQoKYGBgCgpOb3csIGl0IGlzIHBvc2libGUgdG8gaW5jbHVkZSBib3RoIHJlc3VsdHMgZnJvbSB0aGUgbGFzdCB0d28gdGFibGVzIGluIG9uZSBncmFwaCBpbiBvcmRlciB0byBjb21wYXJlIHRoZSByZXN1bHRzLiBFYWNoIHBvaW50IGluIHRoZSBncmFwaCByZXByZXNlbnRzIGEgc29uZ3MsIGFuZCBmb3IgZWFjaCBzb25nIHRoZXJlcyBhIGdsb29tIGluZGV4IHNjb3JlLiBUaGUgYmxhY2sgZG90cyByZXByZXNlbnQgdGhlIGF2ZXJhZ2Ugc2NvcmUgZm9yIGVhY2ggYWxidW0uIEl0IGlzIGltcHJvdGFudCB0byBub3RlIHRoYXQgYnkgdGhlIHRpbSBwZWFybCBqYW0gc29uZ3Mgc2VlbSB0byBiZSBncm93aW5nIGxlc3Mgc2FkLiAKYGBge3IsIGV2YWwgPSBULG91dC53aWR0aD0iOTklIn0KCnBhbCA8LSBjKCJ0dXJxdW9pc2U0IiwibmF2eWJsdWUiLCJwZXJ1IiwiZ29sZGVucm9kMiIsImZvcmVzdGdyZWVuIiwiZGFya2dyYXkiLAogICAgICAgICAib3JhbmdlIiwibWFnZW50YSIsImxpZ2h0c2xhdGVibHVlIiwieWVsbG93Z3JlZW4iLCJtZWRpdW1ibHVlIikKCmZpZyA8LSBwbG90X2x5KGRhdGEgPSByYW5rLAogICAgICAgICAgICAgIHggPSB+YWxidW1fbmFtZSwgeSA9IH5hdmVyYWdlLHR5cGUgPSAnc2NhdHRlcicsbW9kZSA9ICdtYXJrZXJzJywKICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KHNpemUgPSAxMCksCiAgICAgICAgICAgICAgY29sb3IgPSB+YWxidW1fbmFtZSwgY29sb3JzID0gcGFsLCBzcGFuID0gSSgxKSxzdHJva2UgPSBJKCJibGFjayIpLAogICAgICAgICAgICAgIHRleHQgPSB+cGFzdGUoIkdsb29tIEluZGV4IHNjb3JlOiAiLCByb3VuZChhdmVyYWdlLDMpLCAnPGJyPlRyYWNrOicsIHRyYWNrX25hbWUpKQoKZmlnIDwtIGZpZyAlPiUgYWRkX3RyYWNlKHkgPSB+Z2xvb21faW5kZXgsbW9kZSA9ICdsaW5lcyttYXJrZXJzJyx0eXBlID0gJ3NjYXR0ZXInLG5hbWUgPSAnQWxidW0gQXZlcmFnZScsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IEkoJ2JsYWNrJyksc3Ryb2tlID0gSSgiYmxhY2siKSxtYXJrZXIgPSBsaXN0KHNpemUgPSAxMCksCiAgICAgICAgICAgICAgICAgICAgICB0ZXh0ID0gfnBhc3RlKCJBbGJ1bSBhdmVyYWdlIHZhbGVuY2U6Iiwgcm91bmQoZ2xvb21faW5kZXgsMyksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnI+QWxidW06JyxhbGJ1bV9uYW1lKSkKCmZpZyAlPiUgbGF5b3V0KHhheGlzID0gbGlzdCh6ZXJvbGluZSA9IFQsIHRpdGxlID0iQWxidW0gTmFtZSIpLAogICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QoaG92ZXJmb3JtYXQgPSAnLjNmJywgdGl0bGUgPSAnR2xvb20gSW5kZXgnKSwKICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEYpCmBgYApXaXRoIHRoaXMgZ3JhcGggd2UgY2FuIGNvbmNsdWRlIHNvbWUgdGhpbmdzLiBGaXJzdCwgdGhlIHNhZGRlc3QgUGVhcmwgSmFtIGFsYnVtIHRvIGRhdGUgaXMgKipUZW4qKiwgZm9sbG93ZWQgYnkgKipZaWVsZCoqIGFuZCAqKlZpdGFsb2d5KiouIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgaGFwcGllc3QgYWxidW1zIGJlaW5nICBCYWNrc3BhY2VyIGFuZCBMaWdodG5pbmcgQm9sdCBhbmQgdGhlIHRvcHMgc2FkIHNvbmdzIGJlaW5nICoqUGFydGluZyB3YXlzKiogYW5kICoqU3VwZXJzb25pYyoqLgoKIyMgV29yZCBjb3VudHMgYnkgYWxidW0gYW5kIHNvbmcKCldpdGggdGhlIGRhdGFzZXQgSSdtIGFibGUgdG8gZG8gc29tZSBleHRyYSBleHBsb3JhdGlvbi4gRm9yIGV4YW1wbGUsIGhvdyBtYW55IHdvcmRzIGRvZXMgZWFjaCBhbGJ1bSBoYXZlIGluIGF2ZXJhZ2U/IEhvdyBtYW55IHdvcmRzIHBlciBzZWNvbmQ/IFdoYXQncyB0aGUgd29yZGllc3Qgc29uZyBhbmQgYWxidW0/IEluIG9yZGVyIHRvIGFuc3dlciB0aGlzIHF1ZXN0aW9uIGlzIGltcG9ydGFudCB0byByZWx5IGluIGFuIGltcG9ydGFudCB3b3JkIGNvdW50IHN0YXRpc3RpYy4gRm9yIHRoaXMgbWF0dGVyIGkgd2lsbCB1c2UgdGhlIGNvdW50IG9mIGRpc3RpY3RpdmUgd29yZHMgdXNlZCBpbiB0aGUgc29uZy4gQnV0LCB3aHkgdGhpcyBzdGF0aXN0aWM/IEkgY29uc2lkZXJlZCBkaXN0aW5jdCB3b3JkcyBpbiBvcmRlciB0byBhdm9pZCByZXB0ZXRpdmVuZXNzLiBGb3IgZXhhbXBsZSwgaW4gYW5hbGl6aW5nIERlZXAsIHlvdSBjYW4gaGVhciBhYm91dCA3IHRpbWVzICoqKmNhbid0IHRvdWNoIHRoZSBib3R0b20qKiouIEluIGRvaW5nIHNvIHdlIGFyZSBub3QgYmVpbmcgZ3VpZGVkIGJ5IHRoZSByZXBldGl2ZW5lc3Mgb2YgdGhlIHNvbmcsIGJ1dCB0aGUgZGlmZmVyZW50IHdvcmRzIHVzZWQuCgpgYGAge3IsIGV2YWwgPSBUfQpwaiAlPiUgZ3JvdXBfYnkodHJhY2tfbmFtZSxhbGJ1bV9uYW1lKSAlPiUgc3VtbWFyaXNlKGRpc3RpbmN0X3dvcmRzID0gbWVhbihkaXN0aW5jdF93b3JkcyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd29yZF9wZXJfc29uZyA9IG1lYW4od29yZHMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmRzX3Blcl9zZWNvbmQgPSBtZWFuKHdvcmRzX3Blcl9zZWNvbmQpKSAlPiUgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhkaXN0aW5jdF93b3JkcykpICU+JSBoZWFkKDEwKSAlPiUKICBrYWJsZShmb3JtYXQgPSAic2ltcGxlIiwgY29sLm5hbWVzID0gc3RyX3RvX3RpdGxlKGdzdWIoIltfXSIsICIgIiwgY29sbmFtZXMoLikpKSxhbGlnbiA9ICdsY2NjYycsY2FwdGlvbiA9ICJQZWFybCBKYW0gd29yZCBjb3VudCBieSBzb25nIixkaWdpdHMgPSAzKQpgYGAKCiMjIFdvcmRjbG91ZHMKCkF0IHRoaXMgcG9pbnQgSSdhbSBhYmxlIHRvIHVzZSB0aGUgZmlsdGVyZWQgZGF0YSBpbnRvIHdvcmRjbG91ZHMgYnkgdXNpbmcgdGhlICB3b3JkIGNvdW50cyBmb3IgZWFjaCBzb25nLiBCeSBkb2luZyBzbyB0aGUgbWFpbiBvYmplY3RpdmUgaXMgdG8gdml6dWFsaXplIHRoZSBwcmljaXBhbCB3b3JkcyB1c2VkIGluIGVhY2ggc29uZyBieSBhZGRpbmcgdGhlIHRvdGFsIHdvcmRzIHVzZWQgaW4gZWFjaCBzb25nIGFjcm9zcyBhbGJ1bXMuIEkgdXNlIHRoZSBwYWNrYWdlcyBgd29yZGNsb3VkYCBhbmQgYHRtYC4gSSB0aGVuIGZvbGxvdyB0byB1c2UgdGhlIGZ1bmN0aW9ucyBgd29yZGNsb3VkYChmcm9tIGB3b3JkY2xvdWRgKSBhbmQgYERvY3VtZW50VGVybU1hdHJpeGAsIGBDb3JwdXNgIGFuZCBgVmVjdG9yU291cmNlYCAoZnJvbSBgdG1gKS4gSSBwbG90IHRoZSB0b3AgMTAwIHdvcmRzIHNlbGVjdGVkIGJ5IHRoZSB3b3JkIGNvdW50cyBpbiBlYWNoIGFsYnVtIChhZ2dyZWF0ZWQgYnkgdGhlIHN1bSBvZiBlYWNoIHdvcmRzIGNvdW50IGJ5IHNvbmcpCgpBIHNtYWxsIGNhdmVhdCBpbiB0aGlzIHNlY3Rpb246IFdvcmQgY291bnRzIGRvIG5vdCBhY2NvdW50IGZvciBzb25nIHJlcGV0aWl2ZW5lc3MuIFNvIHdvcmQgdXNhZ2UgbWlnaHQgYmUgYmlhc2VkIGluIHRlcm1zIG9mIHJlcGV0aXRpb24gd2l0aGluIGVhY2ggc29uZyBhbmQgYWxidW0uIFNlY3Rpb24gMi42IChUZXJtIGZyZXF1ZW5jeSBJbnZlcnNlIERvY3VtZW50IEZyZXF1ZW5jeSAoVEYtSURGKSkgdGFrZXMgdGhpcyBwcm9ibGVtIGludG8gYWNjb3VudCBieSB1c2luZyBhIG1lYXN1cmUgb2YgdGhlIGltcG9ydGFuY2Ugb2YgZWFjaCB3b3JkIGluIHRlYWNoIHNvbmcuCgotLS0gClRlbiAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvVGVuLmpwZWcpIAotLS0gClRlbiAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvVGVuLmpwZWcpIAotLS0gClZzLiAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvVnMuanBlZykgCi0tLSAKVml0YWxvZ3kgIVtdKFJlc3VsdHMvV29yZGNsb3VkL3ZpdGFsb2d5LmpwZWcpIAotLS0gCk5vIENvZGUgIVtdKFJlc3VsdHMvV29yZGNsb3VkL05vIGNvZGUuanBlZykgCi0tLSAKWWllbGQgIVtdKFJlc3VsdHMvV29yZGNsb3VkL3lpZWxkLmpwZWcpIAotLS0gCkJpbmF1cmFsICFbXShSZXN1bHRzL1dvcmRjbG91ZC9CaW5hdXJhbC5qcGVnKSAKLS0tIApSaW90IEFjdCAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvUmlvdCBBY3QuanBlZykgCi0tLSAKUGVhcmwgSmFtICFbXShSZXN1bHRzL1dvcmRjbG91ZC9QZWFybCBKYW0uanBlZykgCi0tLSAKQmFja3NwYWNlciAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvQmFja3NwYWNlci5qcGVnKSAKLS0tIApMaWdodGhpbmcgQm9sdCAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvTGlnaHRoaW5nIGJvbHQuanBlZykgCi0tLSAKR2lnYXRvbiAhW10oUmVzdWx0cy9Xb3JkY2xvdWQvR2lnYXRvbi5qcGVnKSAKLS0tIAoKIyMgVm9jYWJ1bGFyeSBkaXZlcnNpdHkKCmBgYCB7cixvdXQud2lkdGg9Ijk5JSJ9CnBqICU+JSBncm91cF9ieShhbGJ1bV9uYW1lLHRyYWNrX25hbWUpICU+JSBzdW1tYXJpc2UobnVtYmVyX3dvcmRzID0gbWVhbihkaXN0aW5jdF93b3JkcykpICU+JSAKICBnZ3Bsb3QoZGF0YSA9IC4sIGFlcyh4ID0gZmFjdG9yKGFsYnVtX25hbWUpLHkgPSBudW1iZXJfd29yZHMpKSArZ2VvbV92aW9saW4oYWxwaGEgPSAwLjcsIGNvbG9yID0gJ2JsYWNrJywgc2l6ZSA9IDAuMikrCiAgZ2VvbV9qaXR0ZXIoYWVzKHNpemUgPSBudW1iZXJfd29yZHMpLGhlaWdodCA9IDAsIHdpZHRoID0gMC4xLCBhbHBoYSA9MC4yKSArIGdlb21fYm94cGxvdChhZXMoZmlsbCA9IGFsYnVtX25hbWUpLCBhbHBoYSA9IDAuNikgKwogIGxhYnModGl0bGUgPSAiTGV4aWNhbCBEaXZlcnNpdHkgLSBWb2NhYnVsYXJ5IiwgeCA9ICIiLCB5ID0gJ0Rpc3RpbmN0IHdvcmRzIGNvdW50JykgKyB0aGVtZV9idygpICsgCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGxlZ2VuZC50aXRsZSAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoc2l6ZSA9IDAuNCkpICsgZ3VpZGVzKGZpbGwgPSBGKSArIHNjYWxlX3NpemUoJ051bWJlciBvZiB3b3JkcycpCgpgYGAKCiMjIFRlcm0gRnJlcXVlbmN5IEludmVyc2UgRG9jdW1lbnQgRnJlcXVlbmN5IChURi1JREYpCgpgYGB7cixpbmNsdWRlPUYsZXZhbD1UfQpmcmVxdWVuY3kgPC0gcGogJT4lIHVubmVzdF90b2tlbnMod29yZCwgbHlyaWNzKSAlPiUgCiAgY291bnQoYWxidW1fbmFtZSwgd29yZCwgc29ydCA9IFQpICU+JSBiaW5kX3RmX2lkZih3b3JkLCBhbGJ1bV9uYW1lLCBuKQpmcmVxdWVuY3kkYWxidW1fbmFtZSA8LSBmYWN0b3IoZnJlcXVlbmN5JGFsYnVtX25hbWUsIGxldmVscyA9IGFsYnVtX2xldmVscykKCmZyZXF1ZW5jeSA8LSBzdWJzZXQoZnJlcXVlbmN5LHdvcmQgIT0gImUiKQpmcmVxdWVuY3kgPC0gc3Vic2V0KGZyZXF1ZW5jeSx3b3JkICE9ICJnIikKZnJlcXVlbmN5IDwtIHN1YnNldChmcmVxdWVuY3ksd29yZCAhPSAicmUiKQpmcmVxdWVuY3kgPC0gc3Vic2V0KGZyZXF1ZW5jeSx3b3JkICE9ICJyIikKZnJlcXVlbmN5IDwtIHN1YnNldChmcmVxdWVuY3ksd29yZCAhPSAib2siKQpmcmVxdWVuY3kgPC0gc3Vic2V0KGZyZXF1ZW5jeSx3b3JkICE9ICJ1aG9oIikKZnJlcXVlbmN5IDwtIHN1YnNldChmcmVxdWVuY3ksd29yZCAhPSAiYmVuIikKZnJlcXVlbmN5IDwtIHN1YnNldChmcmVxdWVuY3ksd29yZCAhPSAiaGEiKQpmcmVxdWVuY3kgPC0gc3Vic2V0KGZyZXF1ZW5jeSx3b3JkICE9ICJiZW4iKQpmcmVxdWVuY3kgPC0gc3Vic2V0KGZyZXF1ZW5jeSx3b3JkICE9ICJ3YWgiKQpmcmVxdWVuY3kgPC0gc3Vic2V0KGZyZXF1ZW5jeSx3b3JkICE9ICJ3b2FoIikKZnJlcXVlbmN5IDwtIHN1YnNldChmcmVxdWVuY3ksd29yZCAhPSAiZCIpCmBgYApgYGB7cixvdXQud2lkdGg9Ijk5JSJ9CgphbGJ1bV9sZXZlbHMxIDwtIGMoIlRlbiIsICJWcy4iLCAiVml0YWxvZ3kiLCAiTm8gQ29kZSIsICJZaWVsZCIsICJCaW5hdXJhbCIpCmFsYnVtX2xldmVsczIgPC0gYygiUmlvdCBBY3QiLCAiUGVhcmwgSmFtIiwgIkJhY2tzcGFjZXIiLCAiTGlnaHRuaW5nIEJvbHQiLCAiR2lnYXRvbiIpCgpmcmVxdWVuY3lbZnJlcXVlbmN5JGFsYnVtX25hbWUgJWluJSBhbGJ1bV9sZXZlbHMxLF0gJT4lIGdyb3VwX2J5KGFsYnVtX25hbWUpICU+JSAKICBzbGljZV9tYXgodGZfaWRmLCBuID0gMTUpICU+JSB1bmdyb3VwKCkgJT4lCiAgZ2dwbG90KGFlcyh0Zl9pZGYsZmN0X3Jlb3JkZXIod29yZCwgdGZfaWRmKSwgZmlsbCA9IGFsYnVtX25hbWUpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSArIGZhY2V0X3dyYXAofmFsYnVtX25hbWUsIG5jb2wgPSAzLCBzY2FsZXMgPSAiZnJlZSIpICsKICBsYWJzKHggPSAidGYtaWRmIiwgeSA9IE5VTEwpK3RoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNy41KSkKCmZyZXF1ZW5jeVtmcmVxdWVuY3kkYWxidW1fbmFtZSAlaW4lIGFsYnVtX2xldmVsczIsXSAlPiUgZ3JvdXBfYnkoYWxidW1fbmFtZSkgJT4lIAogIHNsaWNlX21heCh0Zl9pZGYsIG4gPSAxNSkgJT4lIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKHRmX2lkZixmY3RfcmVvcmRlcih3b3JkLCB0Zl9pZGYpLCBmaWxsID0gYWxidW1fbmFtZSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEYpICsgZmFjZXRfd3JhcCh+YWxidW1fbmFtZSwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnMoeCA9ICJ0Zi1pZGYiLCB5ID0gTlVMTCkrdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LjUpKQoKYGBgCgojIFNlbnRpbWVudCBBbmFseXNpcyBhbmQgTmF0dXJhbCBMYW5ndWFnZSBQcm9jZXNzaW5nCiMjIE5DUiBTZW50aW1lbnQKYGBge3J9CnBqJGFsYnVtX25hbWUgPC0gZmFjdG9yKHBqJGFsYnVtX25hbWUsIGxldmVscyA9IGFsYnVtX2xldmVscykKcGpbcGokYWxidW1fbmFtZSAlaW4lIGFsYnVtX2xldmVsczEsXSAlPiUgZ3JvdXBfYnkoYWxidW1fbmFtZSkgJT4lIHN1bW1hcmlzZShmZWFyID0gc3VtKGZlYXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nZXIgPSBzdW0oYW5nZXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW50aWNpcGF0aW9uID0gc3VtKGFudGljaXBhdGlvbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNndXN0ID0gc3VtKGRpc2d1c3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgam95ID0gc3VtKGpveSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG5lZ2F0aXZlID0gc3VtKG5lZ2F0aXZlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcG9zaXRpdmUgPSBzdW0ocG9zaXRpdmUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FkbmVzcyA9IHN1bShzYWRuZXNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1cnByaXNlID0gc3VtKHN1cnByaXNlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydXN0ID0gc3VtKHRydXN0KSkgJT4lIAogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnMgPSBjKCdhbGJ1bV9uYW1lJyksIHZhbHVlLm5hbWUgPSAnc2VudGltZW50JykgJT4lIAogIGdncGxvdChhZXMoeCA9IHZhcmlhYmxlLCB5ID0gc2VudGltZW50LCBmaWxsID0gc2VudGltZW50KSkgKyBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKyBjb29yZF9mbGlwKCkrCiAgZmFjZXRfd3JhcCh+YWxidW1fbmFtZSwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlIikgKyB0aGVtZV9idygpICsgc2NhbGVfZmlsbF92aXJpZGlzKCkgKyAKICBsYWJzKHkgPSAiV29yZCBjb3VudCIsIHggPSAiTkNSIFNlbnRpbWVudCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKQoKcGpbcGokYWxidW1fbmFtZSAlaW4lIGFsYnVtX2xldmVsczIsXSAlPiUgZ3JvdXBfYnkoYWxidW1fbmFtZSkgJT4lIHN1bW1hcmlzZShmZWFyID0gc3VtKGZlYXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nZXIgPSBzdW0oYW5nZXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW50aWNpcGF0aW9uID0gc3VtKGFudGljaXBhdGlvbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNndXN0ID0gc3VtKGRpc2d1c3QpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgam95ID0gc3VtKGpveSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG5lZ2F0aXZlID0gc3VtKG5lZ2F0aXZlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcG9zaXRpdmUgPSBzdW0ocG9zaXRpdmUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FkbmVzcyA9IHN1bShzYWRuZXNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1cnByaXNlID0gc3VtKHN1cnByaXNlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydXN0ID0gc3VtKHRydXN0KSkgJT4lIAogIHJlc2hhcGUyOjptZWx0KGlkLnZhcnMgPSBjKCdhbGJ1bV9uYW1lJyksIHZhbHVlLm5hbWUgPSAnc2VudGltZW50JykgJT4lIAogIGdncGxvdChhZXMoeCA9IHZhcmlhYmxlLCB5ID0gc2VudGltZW50LCBmaWxsID0gc2VudGltZW50KSkgKyBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKyBjb29yZF9mbGlwKCkrCiAgZmFjZXRfd3JhcCh+YWxidW1fbmFtZSwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlIikgKyB0aGVtZV9idygpICsgc2NhbGVfZmlsbF92aXJpZGlzKCkgKyAKICBsYWJzKHkgPSAiV29yZCBjb3VudCIsIHggPSAiTkNSIFNlbnRpbWVudCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKQoKYGBgCgojIyBSYWRhcnBsb3RzCgpgYGB7cn0KcmFkYXIgPC0gcGpbLGMoZ3JlcCgnYWxidW1fbmFtZScsIGNvbG5hbWVzKHBqKSksCiAgICAgICAgICAgICAgICBncmVwKCdmZWFyJywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgIGdyZXAoJ2FuZ2VyJywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgIGdyZXAoJ2FudGljaXBhdGlvbicsIGNvbG5hbWVzKHBqKSksCiAgICAgICAgICAgICAgICBncmVwKCdkaXNndXN0JywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgIGdyZXAoJ3NhZG5lc3MnLCBjb2xuYW1lcyhwaikpKV0gJT4lIAogIGdyb3VwX2J5KGFsYnVtX25hbWUpICU+JSBzdW1tYXJpc2UoZmVhciA9IG1lYW4oZmVhciksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmdlciA9IG1lYW4oYW5nZXIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW50aWNpcGF0aW9uID0gbWVhbihhbnRpY2lwYXRpb24pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzZ3VzdCA9IG1lYW4oZGlzZ3VzdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWRuZXNzID0gbWVhbihzYWRuZXNzKSkKY29sbmFtZXMocmFkYXIpIDwtIHN0cl90b190aXRsZShjb2xuYW1lcyhyYWRhcikpCmNoYXJ0SlNSYWRhcihyYWRhcikKCnJhZGFyIDwtIHBqWyxjKGdyZXAoJ2FsYnVtX25hbWUnLCBjb2xuYW1lcyhwaikpLAogICAgICAgICAgICAgICAgZ3JlcCgnam95JywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgIGdyZXAoJ3N1cnByaXNlJywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgIGdyZXAoJ3RydXN0JywgY29sbmFtZXMocGopKSldICU+JSAKICBncm91cF9ieShhbGJ1bV9uYW1lKSAlPiUgc3VtbWFyaXNlKGpveSA9IG1lYW4oam95KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1cnByaXNlID0gbWVhbihzdXJwcmlzZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnVzdCA9IG1lYW4odHJ1c3QpCiAgKQpjb2xuYW1lcyhyYWRhcikgPC0gc3RyX3RvX3RpdGxlKGNvbG5hbWVzKHJhZGFyKSkKY2hhcnRKU1JhZGFyKHJhZGFyKQoKcmFkYXIgPC0gcGpbLGMoZ3JlcCgnYWxidW1fbmFtZScsIGNvbG5hbWVzKHBqKSksCiAgICAgICAgICAgICAgIGdyZXAoJ3Bvc2l0aXZlJywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgZ3JlcCgnbmVnYXRpdmUnLCBjb2xuYW1lcyhwaikpKV0gJT4lIAogIGdyb3VwX2J5KGFsYnVtX25hbWUpICU+JSBzdW1tYXJpc2UocG9zaXRpdmUgPSBtZWFuKHBvc2l0aXZlKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5lZ2F0aXZlID0gbWVhbihuZWdhdGl2ZSkKICApCgpjb2xuYW1lcyhyYWRhcikgPC0gc3RyX3RvX3RpdGxlKGNvbG5hbWVzKHJhZGFyKSkKY2hhcnRKU1JhZGFyKHJhZGFyKQpgYGAKCiMjIEJpLWdyYW1zIGFuZCB0cmktZ3JhbXMKCmBgYHtyfQpiaWdyYW1zIDwtICBwalssYyhncmVwKCd0cmFja19uYW1lJywgY29sbmFtZXMocGopKSwKICAgICAgICAgICAgICAgICAgIGdyZXAoJ2FsYnVtX25hbWUnLCBjb2xuYW1lcyhwaikpLAogICAgICAgICAgICAgICAgICAgZ3JlcCgnbHlyaWNzJywgY29sbmFtZXMocGopKSldICU+JQogICAgICAgICAgICB1bm5lc3RfdG9rZW5zKGJpZ3JhbSwgbHlyaWNzLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lIAogICAgICAgICAgICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lIAogICAgICAgICAgICBmaWx0ZXIoIXdvcmQxICVpbiUgc3RvcF93b3JkcyR3b3JkKSAlPiUKICAgICAgICAgICAgZmlsdGVyKCF3b3JkMiAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lIAogICAgICAgICAgICBmaWx0ZXIod29yZDEgIT0gd29yZDIpICU+JSAKICAgICAgICAgICAgdW5pdGUoYmlncmFtLCB3b3JkMSwgd29yZDIsIHNlcCA9ICIgIikgJT4lIAogICAgICAgICAgICBpbm5lcl9qb2luKHBqKSAgJT4lIAogICAgICAgICAgICBjb3VudChiaWdyYW0sIGFsYnVtX25hbWUsIHNvcnQgPSBUUlVFKSAlPiUgICAKICAgICAgICAgICAgZ3JvdXBfYnkoYWxidW1fbmFtZSkgJT4lIAogICAgICAgICAgICBzbGljZShzZXFfbGVuKDEwKSkgJT4lIAogICAgICAgICAgICB1bmdyb3VwKCkgJT4lIGFycmFuZ2UoYWxidW1fbmFtZSxuKQoKYmlncmFtcyRhbGJ1bV9uYW1lIDwtIGZhY3RvcihiaWdyYW1zJGFsYnVtX25hbWUsIGxldmVscyA9IGFsYnVtX2xldmVscykKCmdncGxvdChkYXRhID0gYmlncmFtc1tiaWdyYW1zJGFsYnVtX25hbWUgJWluJSBhbGJ1bV9sZXZlbHMxLF0sIGFlcyh4ID0gYmlncmFtLCB5ID0gbiwgZmlsbCA9IGFsYnVtX25hbWUpKSsKZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2J3KCkrIGxhYnMoeSA9ICdOdW1iZXIgb2YgcmVwZXRpdGlvbnMnLCB4ID0nQmlncmFtJykrCmZhY2V0X3dyYXAofmFsYnVtX25hbWUsIHNjYWxlcyA9ICJmcmVlX3kiKSAKZ2dwbG90KGRhdGEgPSBiaWdyYW1zW2JpZ3JhbXMkYWxidW1fbmFtZSAlaW4lIGFsYnVtX2xldmVsczIsXSwgYWVzKHggPSBiaWdyYW0sIHkgPSBuLCBmaWxsID0gYWxidW1fbmFtZSkpKwpnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEYpICsgY29vcmRfZmxpcCgpICsgdGhlbWVfYncoKSsgbGFicyh5ID0gJ051bWJlciBvZiByZXBldGl0aW9ucycsIHggPSdCaWdyYW0nKSsKZmFjZXRfd3JhcCh+YWxidW1fbmFtZSwgc2NhbGVzID0gImZyZWVfeSIpIApgYGAK